 Hi, everyone. Good morning. My name's John, and I'm working on the formality proof language with my co-founder, Victor Maya. What's a proof language? So let's do a quick refresher on type systems. Here's some pseudocode representing an array indexing function in an untyped language. I take an index and an array, and I try to get whatever's inside the array at that index. Get1 is bar because array indices started 0, and get2 is baz. Here's a riddle. If get1 is bar and get2 is baz, what's get1.5? Better question. What should get1.5 be? A runtime error. Indexing an array with a non-integer makes no sense, because an untyped language lets you shoot yourself in the foot and make a bad function call. And this only fails during execution, i.e. when your code's running and can affect the world around it. Runtime errors are tough, because sometimes they do nothing, and sometimes they cause your spacecraft to perform a rapid, unscheduled disassembly. Your code's runtime could be in five minutes on your laptop, or it could be 30 years from now on devices that don't even exist yet. You don't know. It's runtime. By adding some types, we can get the compiler to complain, hey, fix your code. You can't have an index that's not an integer. This error might look deceptively similar to the previous one, but there's one crucial difference. It occurs before your code runs. That is, before it can do any damage. But simple types are kind of inflexible. This function only works for arrays that contain integers. If we want different array contents in a simply typed language, we need a copy, paste, lots of boilerplate. Lots of languages try to solve this with things like interfaces, but there's a better way. Polymorphism allows us to have a type parameter, a, that can get filled with int, or string, or any type that we like. This is really useful. And most type languages stop there. But this still doesn't prevent all runtime errors. We could call get with a really large index and cause an out-of-bounds runtime error. Some languages don't even error. They just dump the contents of memory, and that's probably worse. But if we want the compiler to warn us if our index is bigger than our array length, we're going to need types that depend not only on other types but on normal values. Here, we have a type level number n that tells the compiler how long the array is. Just like we have a type parameter a that tells us what's in the array, n is a type level value that lets us enforce that our index has to be between 0 and n minus 1. The values in dependent types don't have to be constants. They can be the results of computations. This lets us constrain the function so much that we can often guess what the implementation has to be just from its shape, kind of like a game of who's that Pokemon, but with types. In this case, we have a function that receives a number n and returns an array of prime numbers that have multiplied together equal n. Can anyone guess what this has to be? It's factorize. The cool thing is nothing other than the correct factorization implementation will pass the type checker. The Fibonacci sequence would be a type error because the products wouldn't sum to the number. Let's play again. Given an array x's, return an array y's with the same elements, but in ascending order. What does this function have to be? Sort. Anything else is a type error. Those such that are checked statically, which means that you will not go to space today becomes my code is broken and I don't know why. Which is great because compile time is when you, the programmer, are in the process of fixing your code. This is really nice for immutable blockchains, where a runtime error means my code is broken, no one can get their money out, and I can't fix it because I deployed my code to an immutable platform. But dependent types are useful for so much more. If we can do arbitrary type level computation, we can use our type system to declare any combination of properties we want. And then if we write code that validly checks those properties, we've built a constructive, executable proof of the theorem that type represents. This is the Curry-Howard isomorphism, and my favorite isomorphism. Formal logic and software development are actually the same activity. It's just not obvious because the usual syntax is very different. Most math syntax forces you to do the execution manually, and most code syntax forces you to keep track of type information manually. Our goal with formality is to have a language that's really, really good for both software development and for exploring mathematics. We want to make a programming language as accessible as Python and a proof language as powerful as Agda, one that's safe, fast, simple, and portable. We still have a long way to meet that goal, but we've made great progress in the past year. Here's all the type signatures we just went over, but in formality syntax instead of pseudocode. And here's how we declare data types and how we take the tail of a list. The cool thing here is that unlike other proof languages like Coq or Agda, our data types aren't built in to the theory. They're actually just a syntax sugar for lambda functions. This code looks a little scary from a user perspective, which is why we built the syntax sugar over the past year, but it's actually a lot simpler to implement. And our runtime is only about 400 lines long, and our core language theory is only about 1,500. We think it's really important for portability and decentralization to have a language that's small enough that people can implement it or at least understand it themselves. Here's the clean syntax again, you know, now that you know what the lambda encodings look like. Let's talk about performance. A language is great for writing practical software, has to be fast. While formality's runtime is still immature, the language has a lot of features that we think will make it very fast in the long term. Interaction nets is our runtime model, and I think it deserves its own talk since they allow us some really crazy optimizations like optimal sharing, runtime fusion, and here's our nice illustration of what the reduction actually looks like, and you can see the conversion from a lambda term to a graph, and then back. For code with lots of higher order functions, formality is extremely fast right now, but there's still substantial overhead, which makes us only moderately fast on average at the moment. We think in future our interaction net model will pay a lot of dividends here. Performance is really critical to us for getting people to adopt formality and using it to build lots of great software. One interesting thing about these benchmarks is that if instead I call the function not 10 to the 100 times, but 10 to the 100,000, it still only takes like 12 seconds, which is way better than, I think, pretty much any other language that I've used unless you do crazy optimizations. Here's why proofs matter. Here's a sample of some costly issues that have happened at different parts of the stack that perhaps could have benefited from proofs in type safety. Heartbleed, that's just an out-of-bounds indexing error. Now, proofs aren't a silver bullet because all these issues are really complicated, but if proofs can reduce the severity or incidence of these kinds of errors, even just a little bit at the margin, I think it's worth exploring. And in blockchain I think it's especially relevant because the ratio between code complexity and code value is so extreme. Here I just counted the lines in some popular projects, BAT, USDC, and a lot of projects are running at about a million dollars per capital per lines of code. So I think it's really important that if you're writing projects like that, you should put a little extra effort in trying to make sure that the lines of code are actually the correct lines of code. One criticism of proofs is that they pass responsibility for correctness to the specification rather than the implementation and you still have to audit it. And that's completely true. This proofs don't solve having to actually think about your code and reason that is correct. And if your type spec is bad, then your proofs don't help you. But type specifications can be much simpler than the code they're typing. And at worst, act like a compiler check documentation. Here's a little snippet from our ERC-20 implementation and you can see that we have this type specification that says I have a transfer function, the approvals have to be in an old state, that it has to be removed from a new state, and it has to obey a double entry bookkeeping environment. You don't even need to see the implementation to know that if it type checks those properties that it's going to, as long as the compiler is valid, that it's going to be safe according to those properties. The vision is to have formality be a language that can add type safety at every layer of the stack. Having the same language every, means that you can use the same types everywhere with minimal friction. And this is what's awesome about having a 400 line language implementation. We can have the same language infrastructure running inside a web app, smart contract, server, editor plugin, or our test suite. Our next big priority now that the language is pretty stable, is to write the compilers that will let us deploy formality smart contracts, and to continue maturing the libraries, tools, and docs to make that a really great user experience. After that, implementing formality in itself will improve portability even further, and we're gonna see how fast we can push the existing C implementation. The two projects after that are gonna be our package management infrastructure and putting the formality type checker on an Ethereum contract. That enables us to build a completely trustless marketplace for code and proofs. You can submit a formality type to a contract along with a bounty for the first valid implementation of that type. And then anyone in the world can claim the bounty just by submitting the code. No human interaction required. If it passes the type checker, you get paid. And that's formality. Thanks. Happy to take any questions. I don't think I have any time. Okay.