ZK10: Learn Noir in an afternoon (or get your money back*) - José Pedro Sousa

3 Oct 2023 · 1:05:20

José Pedro Sousa runs a hands-on workshop on the Noir programming language for zero-knowledge circuits, recorded at Zero Knowledge Summit 10 in London. The session covers writing basic ZK circuits in Noir, generating proofs in the browser, and working with recursive proofs.

Speakers

Topics

Transcript

Thank you all. Just going to take my notes here. Okay. Hi. Uh glad to see you all. It's been great, right? First this uh Yeah, first day. It's actually the only the only day, right? Cool. Yeah. Yeah, can you hear me better this way? Okay, cool. I'll just one thing before I before I forget. For the questions, there's a mic here, so just pick it up. I'll forget it. So, yeah.

Cool. So, Noir. Um yeah, I won't get your money back, sorry. That's uh That's it. Uh there's there's your It says that I won't do it. Um so, Noir, let's just go on our rundown and then let's talk a little bit about Noir and everything else. So, let's talk about ZK. I think this part is pretty everyone should be comfortable with this. Um then I'm going to talk about Noir and why is Noir mostly why um before the how.

Um then I'm going to talk about our project. So, yeah, just a small uh thing you could follow along. You can follow along if you have your laptops. Otherwise, just yeah, the only Um and then and then yeah, let's finally hack something and try it. So, we know that ZK proofs are powerful. I think that's everyone knows that if you're here. Um but with great power usually um come univariate polynomial commitments.

And if you're like me and you struggle with this kind of math, then yeah, maybe Noir is exactly what you're what you're looking for. Um we need these kind of usable ZK-DSLs you can write uh just as the same way as you write a normal program. So, obviously, I'm kind of excluding everyone that doesn't know how to code. But still, I'm including everyone who knows how to code, but don't understand don't have the time uh to understand the math behind it.

So, we had to copy basically we we decided to copy a syntax of a nice language and Rust is a nice language. So, we're like, okay, let's do let's do Rust. And and that's basically how it started. Um so, if you try to find the difference between one of and the other, probably the Noir one is going to be a little bit simpler, but they still have the same syntax. Uh they look very similar. Um but again, yeah, it's just a syntax. Once you start scratching the surface, um it's going to be very very different uh the way it works. Um yeah, and I'm going to show you why.

So, if you try to spot the difference between these two images, um yeah, that's kind of a me right because I have the two different colors. So, kind of kind of guess that one is Noir and the other one is Rust. But as you can see, apart from small things like assertions, for example, uh those are things that you only get in Noir. Everything else is just the same. So, we want to write codes instead of write circuits. Circuits is basically yeah, if you if you've been here for a while, maybe maybe you wrote your circuit you draw your circuits and then connect the wires and cetera.

And that's that's nice, but it's kind of a different paradigm. We want something that developers are used to work with code, programs, smart contracts for Aztec sandbox. So, yeah. So, we want to target not only like the beginners, but also everyone else that just I just want ECDSA signature verification. I don't really know I don't really have I don't want to implement all thing. Just give me a module I can use so I can develop further. And so, yeah, we kind of want to target everyone, not just not just the the beginners.

And actually, we have like big projects being built on Noir and they are just fine. And so, yeah, it's not not just for pros. It's for everyone. So, our build plan. Um So, basically, I'm going to have like three or four chapters. Let's see how much time we have for all of that. So, basically, I'm going to just introduce Nargo. So, is it cargo? Nargo? Yeah. It's kind of It's like a package manager. Yeah, you can use that to init a project and etc. Then, I'm going to go over the Noir syntax. Just very basic things. You can always go on to the docs and learn more.

I'm going to write some tests. I think tests are there already. Yeah. And and then just how to generate a verify proofs. And then, the standard library, it just we're just going to go over maybe one or two examples of the standard library. How can you use it? Um And maybe like using another libraries. And then, the good stuff, which is basically the browser. How how can you how can you have proofs running on a browser? Um So, yeah, literally on your machine or or in a mobile phone or something and and then maybe a surprise let's see it's all be

it's all be a cool one. Yeah, I'm going to leave out the proof I'm proof on chain because it's just everyone knows how to apply to how to apply smart contract I guess. And if you don't that's okay just talk to me later I'll I'll I'll work I'll help you but yeah I'm going to leave this out because it takes a lot a lot of time and yeah it's just just yeah it's kind of difficult. So yeah finally I think let's start. So I have here my three QR codes I guess the most important is the latest one if you're following with your laptop because it has some resources.

Yeah there's also the Noir docs which have everything that you're going to be using today. And also my limo what's it called yeah it's kind of a link tree web tree link tree. You can there's all my profiles and etc. for if you want to follow me. Okay no phones in the air. I promise I'm not going to pick a gun like a shotgun and shoot.

Promise. So you can you can put your phones in the air. Okay sorry still phones in the air. Phones in the air. Okay cool.

Um so yeah, if you if you didn't pick it up, just just tell me. Um it's a GitHub repo, so it's no no no big deal. Yeah, it's this one, Noir in an afternoon. So Noir Noir long Noir lang {slash} Noir in an afternoon and there we get it. Cool. So, let's start. So, here's the here's I was working on the cheats. Uh cheat codes. So, let's start with something. Uh this is the repo. Um I'm just going to basically install Noir up. So, if you're used to using like Foundry up or Rust up, it's basically like a nice tool you can run.

Um and basically um get get Nargo there and then you have all the tooling you need to start developing in Noir. So, basically you go to that repo and here you have the readme, you can basically go and copy this line and run it. Uh I'm not going to run it because I did it already. Um but yeah, you're going to have this tool, Noir up. And this is really cool uh tool. You can basically use it to install different versions branches PRs, commits, repo, everything. Um it's really a a nice tool. So, if you have it already, or better yet, if you don't have it

already, just let me know. Okay, cool. I assume everyone has gone through this. Then, you can install Nargo. Um so basically, if you're finished that, maybe you need to like restart your your terminal because of the path needs to be there. Uh but you should get Nargo version and you should get some kind of version. Uh oh sorry, you would need to install Nargo first. So, you go Nargo app. Um and I'm going to tell you to install the version 0.11, okay?

Um I'm going to say this one this one because it's a bit faster, but it's not stable yet, but it's cool. I tried it. Trust me, bro. Um so, you can install 0.11. If you do Nargo app and uh it will install the nightly, which is 0.1 0.12 and yeah, I haven't tested that one so it's cool to use 0.11. And it could take a little bit because of the SRS, which is basically the ceremony that we did in 2019.

Uh yeah, it's it's needed this for for our circuits. So, at the end of that, you should have Nargo and you should get uh you should get 0.11. Any issues so far? Okay, yeah, it yeah. Yeah. Okay, I think I can go yeah, can move on and then you'll definitely catch up cuz this part is very easy. So, it's basically just starting a new project. So, I can just I can go um There's basically two very similar commands. One is new that will start in a new directory. Uh init is going to

start in the current directory. I'm saying this because I also don't remember which one is the So, ZK Summit. So, it will create a new project ZK Summit here with uh two uh a folder and a file here. Basically two files actually. Um And this a basic circuit. Uh I guess the the most basic circuit. Um which is Do you think we should zoom in a little bit? Yes. Yes, definitely. And maybe we also turn off the lights because it's a little bit too bright.

Is it cool like this? Yeah, the lights. There are lights. Maybe Thanks. So, this is a very basic circuit. You have basically the FN syntax just like Rust when you define a function. You need to have a main function in Noir circuit. Not in the Aztec contracts. Uh that's a different thing.

Here they don't have a main function. Here you have a main function because that's what you're going to actually run. And then you have like um variable syntax. It's just like Rust. Except you have this little thing called field. So, those of you that know cryptography, especially those who understand it more than me, which is not difficult. Um you you have this You can treat this as kind of some sort of Oh, cool. You can treat this as some sort of like big integer or something. You can make some some arithmetic with it. Um but for example, you can't use it for comparisons. So, yeah, we still can use like U ints.

But for this example, I'll just go with with field. Um if you want to define like an array, it's just like in Rust. You go and say how how many fields you have in that array. This needs to be known at compile size at compile time. Uh the the size of an array. Just like with every ZK language, I think. Um There's this public keyword. So, we kind of think that privacy is the norm. So, it's normal to be to have privacy. So, you only say what's public. That makes sense. It's like So, basically, once you give this to verifier, the verifier will only know the value of Y. Value of X is kept only to you. Only you know this.

You want to prove that. And then we have addition, subtraction, multiplication, etc. So, you can have like let's see equals to X + Y. Um you have like shorthand operators. So, if I make less like this let's If I can make this mutable, I can go and say Z plus equal one. For example, that this is okay as well. Um so, we have these kind of shorthand operators. Then we have like for loops. You can go and say for let I Sorry, for I in Oh, thanks GitHub. You You can You can make for loops here.

Um You can have if else conditions. If I say like if X I can say X Oh, yes, I can. I can say like if X is equals one, I can do something. Otherwise, just do something else. Um Again it's like basic control control flow stuff that we are used to work with. And then we have this assert keyword, which is basically if you want to prove something, you need to prove some assertion. You need to make some need to assert something. You're going to say, "Yes, this only verifies if this is true." And so, this will only verify if X is different from Y.

And so, that's That's the assert keyword. Basically, putting a constraint into your your program. And then another thing that's really cool that we can have is structs. And so, you can have like struct struct person, for example. Okay? So, one example it's like you are you are Brad Pitt and you are you are the owner of a a fight club. And so, you want to prove that someone knows the password of to enter the the fight club and has like the minimum required age.

Um and yeah, but you don't want don't want people to tell you their age or the password. So, for example, you can have like a struct and say like a person that has a certain age and say age is a it's a field as well. And so, then you can also like declare globals and say global minimum age and say global minimum age is going to be 18. Um And so, yeah, basically you can have like age um you can have uh a password.

That's also only known to whoever is is uh saying the password. And then you have like password hash um for example, password hash that's going to be the password that like the hash of the password. Everyone knows that. That's okay cuz it's hashed. So, um So, in our example, yeah, someone could um prove that can they can enter your your fight club and fight to death. Um Then basically um yeah, another thing that's really interesting and I should mention is the return value. So, if you say let's say that this circuit returns something,

uh you do it just like in the rest, uh but when you pass it to the to the to your uh program to the I mean when when you use it, you basically have to pass it as an input. Because just basically what it says is just it's just like um it it works like if I would say return here, it's going to be also a public field. And so and then just at the end of whatever calculations you're making and then it's all say, yeah, just assert that's the return is equal to whatever whatever you did. But this is not so cool. So the guys with Noir team basically just

implemented this nice return. And that's why it needs to be public because you're actually passing it when you verify the circuit. And so yeah, that's just one of the questions that we have sometime. Why why does the return value needs to be public? Um that's the reason. So you need to pass it when you when you when you verify your circuits. Cool. So for tests, we actually have now like tests failing in but I'm not sure if that's in in 2011. I'm not sure so yeah, but basically you were going to have or you have already tests that are supposed to fail, which is cool and we didn't have for for

we didn't have that for some for some time. Um and so let's say let's forget about the password part and just remove this and let's just assert that the age is uh it's bigger than minimum age. Sorry. Um sorry, not age. Um I'll just actually pass a person and say yeah person. So it's um a fighter.

Fighter is a person and let's say that person fighter. Fighter age is uh bigger than minimum age. And yeah, basically now I'm just going to instantiate the person and say let's Brad Pitt. It was Brad Pitt, right? I did it. I'm Yeah. Yeah, yeah, that's true. Okay, so yeah, 55. Okay, I guess GitHub knows that Brad Pitt is Is it 55? Is it I don't know.

He looks younger though. Uh 59, yeah. That's Okay, so I'm now now I'm just passing this to this person basically to to to my to my to my circuit. And this should hopefully fail hopefully pass. Let's say. So, the way you run Okay, it's already complaining about something. Comparison Oh, okay, needs to be an integer. Um as U8, for example, like as U8 and Yeah.

Um yeah, I'm just casting just casting this to to integers. The way you run it, you just go and run the test. Uh okay, I need to ZK summit. Run the test. And it passed. So, seems like Yeah, Brad Pitt is allowed to to to fight. But if he if he was 5 years old, which he was at some point, uh it will fail. And so, yeah, it it failed. It just the constraint failed. Uh now you ask me just like, "Okay, it's cool but sorry, I need to unlock this.

And he Yeah but you're not actually proving something. You're just checking that the syntax is correct." That's true. That's what the test does. If you need to if you need to do something else, then you you need to actually need to prove something. And let's go over that. So, first of all, we need to basically create the files that will go and generate the proof and verify. So, I'm going to go and say nargo check. And that will generate my prover and the verifier. You see that verifier knows nothing. It's like Jon Snow. Knows nothing. Uh but But here like in the prover, the prover knows the age. So, prover is hopefully Brad Pitt and he's

his passport and and verifier is whoever is controlling the the border or whatever. Enters to the fight club. And so here you you have it. So, you just go and put your data in your in in the prover. Say 55. 59, right? 59. And you go say nargo proof. And it will go and generate the proof and say Yeah. Here is it. Here is our proof.

Doesn't Doesn't Yeah, it's kind of difficult to read, but it's a proof. It's kind of small as well, which is what we want. Just mark. If I put something that's it's not valid like five, it will just fail to actually create the proof itself. It's an cannot satisfy satisfy constraint. So, I have the proof here and I want to verify that. So, just go and run nargo verify. So, you see that this is very straightforward. There's There's There's no math here. There's no difficult steps here. Just go Just running nargo commands and writing rest.

Right? Oh, yes, there's a question? Here? It's this It's cuz it's a struct. Yeah. Yes. Basically, the syntax is you put that specific instance between those square brackets. You put it in that ruler function. Let's say we have fighter one and fighter two. Could I have both in the same file the two instances?

Yes. And then you pick one by control flow. Um yeah. Yes. Actually, the circuit will will go on and use both and then just choose the the the branch that useful. Um so yeah, you could do like fighter uh fighter two. Fighter two and say like the age of the fighter two, which uh is 50 60. And then you you can you can have like here fighter two. Uh I don't know if this is what you're asking. And then you can like have the control control flow choose what branch do do you want to But there's no way of just passing like um

Yeah. Yeah. Yeah, it needs to be known at compile time like the size of yeah, how many arguments are passing etc. Yeah. Um Also, as you see like this is it. This is this is Noir. Okay. Thank you. I'm kidding. There's there's more to it. Sorry. Um Yeah. I mean, there's yeah, it takes takes a while.

I think part of it is not not only creating the the proof itself. It needs to create the witnesses as well. And so yeah, there could be parts of that that not that are not as optimized. I guess you're going to be surprised when I show when I show the the browser, which is exactly the same example. Oh no, uh it's it's it's similar simple example. And you're going to be surprised how fast it is actually. So, So, yeah. But, you should you shouldn't you shouldn't definitely not like use use Noir proof for benchmarks. Um yeah. You should you should basically get the get in the um Noir file and then compile it and then feed that to a to a back to to a to a back end like Rostenburg, for example.

And then you can make some some some benchmarks on that. Yeah, because Noir proof I mean, it's just a just a CLI tool. It's meant to be it's meant to be easy to to to run not not like the fastest thing. Um Cool. Uh so, I said that there was more to it and of course there is because otherwise we'll be kind of constrained with how many how many things do we have? And so, if you go to noir-lang.org, you're going to see I'm going to make this a little bit bigger as well.

You're going to see basically the docs. I'm going to choose the dev version. I know this is about 11. I don't even know. Uh but, here you have like Noir though everything I said basically and also how to generate a solid verifier. It's very easy. And and then you have like all the language concepts that I've just introduced. Fields, integers, bool boolean strings, arrays. You can make you can console log stuff. You can you can use references like rest references. Um you can use vectors to resize arrays and and yeah, it's really cool.

Um And logical yeah, and there's also unconstrained functions which is yeah, it's another talk. Uh But, it's it's really cool if you if you want to explore unconstrained functions as well. Um Yeah, so and then there's this thing called Noir standard library. So, if you're used to use like low level low level languages, you know that there is a standard library that can optionally import or not. And this in this case it's kind of the same thing. We have some primitives that we can use and you can use out of the box when you use Noir.

Uh for example, hash methods. You have like um bunch of hash methods. Some are better than the others for whatever reasons you're using them. Um and then yeah, scalar multiplication. Another one that's really cool is EC SS intro verification. Um yeah, and Merkle trees, stuff like that. And so we're going to use this because we want to prove that um Brad Pitt um yeah, knows the password as well. Not only he has the the age, but also knows the password.

Um so Oh, regarding regarding uh benchmarks, one thing you can do is just go and say "Noir go Sorry, Noir go info." and get the number of the gates. And I'm going to go on a side quest here to explain what is this thing ACIR. Um so basically Noir is just a language. As I said, it's just a shell. Uh you compile um you compile Noir go compile Noir circuits to this intermediate intermediate representation um which is ACIR. And that's going to be fed into your back end. And so you're going to see that this only has

19 opcodes and 2K almost 3K um gates. And basically uh you can um yeah, you can use that to benchmark and try to at least compare circuits within the same the same back end. Um So for the password, let's use Poseidon. I guess it's a nice nice uh nice function for for ZK. Um so I'll just copy this basically and say I just put it here so I I don't forget.

And so for the fighter person, and then I'm going to just say password and uh password uh it's a field, yeah? It's a Does it expect a field? It's a field. Yeah, it's a field. A field password and a password hash. This is public. So for that we need to basically calculate what's what's the password hash beforehand. So if you don't trust me, you can basically run this script and you're going to have like the the the hash that you need. Um and you're going to confirm that my the thing that I've put in the read me

here, it's actually true. And so let's say that this this is one, two, and this is the hash of one, two. So just going to go on my prover uh actually on my test run and say um this is my password, one, two. Not a great password, to be honest. And and then the password hash. And finally, I'm going to assert that So not need to calculate the hash and say uh it's just like this, actually, yeah.

Just hash. Hash plus I then this is the curve. And and yeah, hash two because it's it's two, and then we just go and let's just assert. Thank you, GitHub. Um one thing that's missing, you need to import the standard library. Um use dep std. Okay. Cool. Those of you following along, I've written a lot, so let me know when That's it. Is it cool?

Shouldn't you change this line two to the password from the line below? Line 11, sorry. Uh Yeah, the the hash and brackets one two, so it's a constant. Uh yeah, that's true. Yeah, you're right. That's password, yeah. Thank you. So, if I run this, um yeah. It's it's one two Oh, it's sorry, it's a it's an error.

Okay. Cool. So, if I run this, I'm going to run Narwhal test. And yeah, it's passed. Cool. Uh So, yeah, should I try to make it fail? I'll try to make it fail. Is it fancy run test index work? Sorry? Is it fancy run test index work? Uh yeah, I can try. Uh I remember it was like uh should fail something like that. It was like test should fail I think.

Oh no, I meant the one you click in VS code. Oh, this one. Yeah, yeah, it should work. Okay, sorry. It It fails because of the test should fail. Yeah, so yeah, that's that's cool. Thank Thank you for pointing this. I'm already used to have this and also for compiling and executing you can there's this handy VS code extension for Noir that you can you can use. Um Thank you. Yeah, there's there's a syntax should fail and basically you can have tests that expect to fail.

Cool, so let's go let's go basically create this proof. I'm going to put that. It's already in the readme in a nice tunnel format. So I'm going to put it on my prover file and say this is password. This is password hash. So I can go and say nargo prove. Um Expected argument password.

Okay. Seems all right. I don't know what I'm doing wrong. Maybe Maybe it's expecting a different tunnel syntax for you right? No, I think I think this is correct. Um I was just going to remove like the struct itself and say edge. Maybe. Um field this is edge.

There. Um Uh okay, yeah, because of the test. Okay, cool. So, I have my my proof here. So, again, let's just go and run our going for just check how much this hash cost does. Um Yeah, it kind of cost a lot of AC codes, but the back-end circuit size actually is not too big. It's 5K.

Uh for Poseidon. So, yeah, let's let's not try let's not try get check. But, you can you can check it. Um it's obviously it takes um actually less AC codes, but back-end size kind of um it's much bigger. Um yeah, you can use you can just do the same way. I actually have an example here. I just want to save the time for other stuff. So, um then you have uh let's say that you want okay, I want to another dependency. Um I want a silly standard library is cool, but I want something else.

That's okay. You can you can go on your Nargo tunnel and just put it here in dependencies. So, CK sync. Oh, okay. Not not CK sync, but I like AC recover library, which is one of the first, I guess. Um and you can say basically just put your tag here. Um just copy copy here from my notes. Uh you can say it like the GitHub, whatever. Uh so, AC recover Uh just this one.

Just paste it here and then I think uh I think that's it. I'm not sure if I need to put the directory. Anyway, let's try. And yeah, basically you can you can import the ECRecover library just the same way as you did with the standard library go. So, use dependency and then ECRecover. ECRecover is basically it mimics the Ethereum recover um function. Basically, gets an address from from a ECDSA signature. Um yeah, this is this is a nice little um library that I like to use. So, in this case, you know, let's not just

I think I I made my point on this. Cool. So, you tell me, and now what, right? Should I pass the I mean, what How does this help me? Uh and I can tell you you can put that on a Solidity verifier. You can generate a Solidity verifier from uh from a Nargo uh from a Noir circuit. So, you can go and say Nargo code gen code gen verify and let's just wait for it. Wait for it.

Okay, and here is it. It's just Yeah, it's a it's a it's a smart contract uh which was written by very smart people and which I don't understand any anything that's here, but yeah, it just stores a verification key and and the hash. Um and basically, you can use it to to verify. So, you can go and just check the verify function and say exactly what does it expect to to get. And you can deploy this contract, you can wrap this contract um into into your own contract and like with just use it in your regular um web search flow on Ethereum or whatever EVM you're using.

And then there's the cool stuff, which is I mean I I like it. It's cool stuff not Okay, yeah. Question. I'm going to say a lot because I don't know the exact but I think 400k. Yeah, I think it's a bit more than than the than the turbo verifier. But it's faster. Sorry. 400k. Yeah, it's It's not cheap. Yeah.

Yeah, it's constant. Yeah. Yeah. That's that's that's Um Yeah, it I mean Yeah, I mean it it it will it will increase yeah with the with Mhm. I mean Yeah.

No, it's going to be about 400. Yeah, if you if you if 400k if you if you deploy it now. Yeah. Um Yeah, with optimizations I mean you need to optimize you need to compile this in an optimized way. I think with some runs of optimization. I've I've really used it five five 5,000. Sorry. Yeah it's also going to complain that verify is not used and that's because it's I mean it's a function signature that's being used and so some compilers will complain and say yeah, you're not using this.

You're just calling the function signature directly. So it's most of it is actually assembly, so Cool. Now the cool stuff. So let's say that you have a browser and what I want is what I want is this. I want I want basically on the browser I want to prove that X and Y are different. And yeah, it's just a very basic circuit. And this is like the end goal that we want to arrive here. Just go and verify calculate verify off chain. I'm also verifying on chain because I have a Yeah, it's I think it's on Mumbai. So Yeah, you basically This is what we want for for this

example. Yeah, this should fail actually but it's it's spinning. I need to fix this. Yeah, but that's this is the this is our end goal. So let's go over a little bit of the code just to Here's this browser thing. And so it's a Next.js. So it's kind of there's a lot of boilerplate. That's why I put it here. And there's a page, just one page, very basic. And here is like the the main component. So if you're used to React you're going to find it's useful.

If you're not, that's okay. It's it's it's JavaScript basically. And yeah, basically what you're going to do is just some some person's going to input whatever values they want. They are going to calculate proof. And calculate proof will go on this class that's we're going to try to implement. And that that's it. Basically the class is is here Noir and and our goal here is basically to to create this create this class. Actually I'm actually I'm not going to write them. I'm just going to copy it from the cheats here. This is basically just the Noir starter example that I showed in

the beginning. But I remove a lot of things just to make it easier. Um And so yeah, basically just just go over like the imports just for so I can clarify something. So You see the first one is like Afflict. You need to install Afflict because yeah, there's some inconsistency where the Plonky expects non-compressed circuits, but the the ACVM, I'm going to explain what that is, expects a compressed circuit so we need to decompress it.

Uh and then we have like the actual backend, the ACVM stuff that we're going to need, and then ethers because I'm lazy, and then some type because it's TypeScript and they're going to complain if I don't import this. Uh and so before what is this ACVM thing about? So remember that that when I said that when you compile Noir into something, it will compile into a ACIR, abstract circuit, um intermediate intermediate representation. That you're going to feed that into this ACVM. Um which is abstract circuit for the machine, I believe. Yeah. Yeah.

Um that will basically translate your ACIR into whatever your backend is is is looking for. In our case where backend that we like to use is Plonky, and so that's why I'm importing like these three pieces, basically. I'm importing I'm importing the ACVM because I'm reading directly from the AC here. And I'm importing the uh back end, which is here, for example. One thing I didn't say is like in this case, you are expected to already have your circuit compiled. Um we are actually going to um Yeah, we're working on Noir WASM, which will basically compile on the fly as

well. But for now, I just Yeah, you just compile with Noir compile. And Noir compile. And And it will generate this nice file that you can import. It's just just a JSON. And And so, yeah, that that's it. So, I'm going to go back to my cheats and say it's a class. So, I'm going to just go until the inits, and let's talk about it. Um So, I made it a class, uh but you could you can just use it separately.

Um So, basically, um I'm passing already the circuits, like the compiled circuit, in my web page. And then I need to init this init Noir. So, the ACVM, you need to init for the browser, not for the node. So, if you're going to see like the Noir starter, there's actually a conditional on whether it's on the browser or not. And then you're I'm going to import like the bytecode from from my circuit, the compiled circuit. Uh I'm going to decompress it because I'm going to need it uncompressed for the for the Barretenberg.

And then I'm going to initialize the Barretenberg. So, this is multi-threaded, so I'm I'm just asking for four threads. I could make it more. There's a point where it's actually uh it's not faster. I I I think it's even gets slower if you as you get just too many threads for your for your stuff. But yeah, four is okay. Um And basically, yeah, I'm going to init this API. Going to get the circuit size because I need to um yeah, basically um initialize my CRS with that. So, so I need to get circuit size, I need subgroup subgroup size, and then init the SRS, which is the

which is the the ceremony that we we did that you need for for your proofs. And then the the AC composer is going to be using for generating the proofs. So, this is pretty much copy and paste, and we are basically um abstracting this away with a new library that's going to come in a few days. Uh that's going to be abstracting this away. Uh and so you don't even need to think about init. Uh I just go and import that library. Uh it's really cool.

So, this is the init function, and then the witness. So, if you're used to ZK, you need to generate witnesses, which is basically um yeah, basically pass your inputs and and generate something that you can use to prove. Um And so this is the generate witness function. It's basically just it expects a map. So, I'm going to That's That's your where I'm lazy because I need to pad to pad each input into a 32 bytes.

And I'm too lazy, so I'm just using ethers for that. Uh I just go and and pad because let's say that you have your input is one, two. Um It's like one, two. Uh it actually expects like 0x 0x then 31 zeros. And then one, and then so and same for for Uh again, this is something that's going to be abstracted away for now. This is what we have. And yeah, and then finally you have like your witness map. So, you're going to pass uh it's to your ACVM and and get your witness map and the buffer because it's um needs to be compressed.

And this is will get you the witness. Now, for the proof, this is the good stuff. Um So, inner proof uh I think I copied this from the wrong place, I suppose. Let me check. This is from from the other example. Yeah. Okay. Um I'm just going to copy the uh and generate proof.

Yeah, here. Generate proof. And yeah, just going to remove this. Kev is probably laughing right here right now and say, "Yeah, I remember that." Okay, so this is because of recursion if you need to use this for for recursion. So, yeah, I'm decompressing my my witness here. Um I'm going to pass it to my back end to generate my proof.

And then I get my proof. It's really cool. Now, I need to verify it. I want to verify that. So, I'm going to go and verify my proof. And say here, "Verify my proof." I'm also going to remove this. Uh it's kind of the same thing. You just go and verify your proof. And then finally, I need to destroy my API so it doesn't clog. Um, so I just uh this.

Cool. So, it's a very basic example and as I say, it's going to be even simpler um, with the new library. Sorry, code lens. Of course, so hopefully this doesn't have any errors so I can go and just run my run my my thing here. Uh go as browser. Oh sorry. Browser.

I'm going to say yarn. Uh, it only has no modules, but that's okay. And again, run dev. Uh, this will as you see like in package.json, it just goes and just runs next. There's There's no no big deal. Oh, port is in use. Okay. That's okay, I can use 3001. Oh, cannot read properties of undefined.

Uh, I don't know. I maybe I'm importing this from uh, new noir. Oh, here. Yeah, it's expecting the the circuit here. Um, so I need to import it. Oh, import um, circuits from circuits and then targets. And then, oh, it's still call noir start.

So, I'm going to say noir circuit, yeah, hopefully this will work. So, it's it's initializing and remember that init function that I was mentioning? Yeah, it's initializing that. Actually going to start a console here so you can see it like the output. Oh sorry. Um so, it's initialized so I go I can try that and get some error. Uh so, expression has too many unknowns. Uh I don't even know. I'm going to just copy the sheets. Maybe I missed something.

Cool. Uh Yeah, I copied this from from the wrong place. Uh maybe I'm going to copy it from uh Noir starter. It's here. So, I copied it from the from the surprise example. Yeah.

This looks like it could work. If it doesn't, I'm just going to going to give up. Yeah, okay, cool. So, basically that's it. Uh just you see it generated a witness um then generate the proof and then it verify the proof. And that's it. Uh then the on-chain part is is on Noir starter. You can go there and see uh and see that working. Cool. So, now for for the surprise, it's uh recursion basically. Uh so, what is recursion? It's This is all cool, but let's say that you want to verify a proof within a proof.

For example, if your if your circuit is too big and and you're going to spend all the gas and for example, maybe it will be worth to to verify that proof within a proof. And so, that's where recursion comes from. For example, you can have a game like a turn-based game where nothing needs to go on chain because you can you can I make my turn, I make my move, I send it to the other player, the other player verifies that proof within a proof, and also generates his is is play, and then so back and forth.

And maybe basically have this state channel where only like the last proof needs to go on chain. That's really cool. That's I'm very excited about about recursion. And so, I yeah, basically I'm just going to show you how how does it how that works. So, um our examples. Uh here is it. So, in our examples is another um um report that the the roll team has been putting together. So, that there's examples for using with the voting, and recursion, and the working progress, which is stealth drops. Um which is really cool uh project as well.

And so, here there's the recursion. So, I'm going to basically I have here the the so you so you don't have to I have here the code. Uh and basically I'm going to just show the just going to show the circuit so you can know what I'm talking about. You see, there's this main circuit. It's very easy. The same basic X different from Y example. And then, I have another circuit which is this.

It's not it's not complex. It basically says STD verify proof. So, I passed the verification key, which is needed to verify a proof. I also passed the proof, obviously. That's what I want to verify. I'm going to pass the public inputs for the inner proof. Um passing the the hash of that key because that's Yeah, that's could be used It could be used for some for some back ends. And then input aggregation object because you're actually not It's kind of a folding, right? So, you you you you pass you pass the aggregation from the previous proof uh into this proof. So, yeah, if you would like you can use Basically, this is the recursive

um the recursive proof. There's no need to have another one. Unless you're like For example, you can have two of them if you want to verify, for example, a Merkle tree. If you want to just um Yeah, recursively aggregate um the hashing of of the Merkle tree of a Merkle tree. And so, yeah, we have this recursion. We have this this two circuits. And then I'm just going to change my Noir class to basically verify the inner proof and generate the inner proof and the outer proof. So, inner proof is Yeah, the one that you're the the initial proof. And then outer proof is the recursive one.

And so, yeah, I just basically the same thing. I just need to add this little um API calls that basically gets a verification keys and hashes them and etc. That's really cool. That's available in in in the Barretenberg. So, you can basically get everything you need for the public inputs. And then generate the verify outer proof, verify the outer proof, uh everything. And and run it. And so, I run it already. It's on port 3000. That's That's what was calling port 3000. So, you're going to see that on the surface it actually looks the same thing because it is.

Right? It's It's the same It's the same inner circuit. So, there is no change in what I'm putting in here. Um you're going to notice that it takes a little bit more to initialize because yeah, you're actually initializing twice the Groth16 API, so it also uses more resources obviously. And also, the proof will going to take a little bit more to generate. And so, it was very very fast to generate the the inner proof and and to verify that. And then, you see the console log just gets the proof like the the proof just just as the the back end expects it, and verification key, and also the hash.

And and then, generating the witness for the for for recursive circuit, and and creating that proof. So, let's wait. That's the part that takes a little bit longer because it's the recursive circuit, and it's not simple. Uh but hopefully, um while I'm speaking still, it will work. Um but again, you can you can just pick this proof, put that on a smart contract. Um And so, this basically allows for the most amazing use cases you can have in ZK, right? Because it's almost you have like a constant-size proof for whatever you

want. And so, oh, your circuit is too big. No problem, just split it into, right? And just verify those two parts. Um your Merkle tree has too many too many levels. No problem, just just prove like two halves of the of the of the lower part of the tree, and then verify that those two halves in the in the in the in the recursive proof. So, pretty much anything can be done with with recursive proofs. So, yeah, generated the proof, and now verifying the proof. This takes a little bit because of the verification key, I'm kind of taking it twice, and I shouldn't. So, that's why it's verification's cuz I I've I've done it already.

So, yeah, it's verified the proof, and yes, took less than 1 minute. Um So basically init the SRS, make the proof, load the verification key, and verif- and verify. So, if you optimize this, like by storing the optim- the verification key, for example, you can make this much much faster. And so, yeah, I'm very excited about about recursion on on Noir. Cool. Um yeah, that's it. Um I mean, I could be here all day uh speaking about Noir because I it's I absolutely love this language.

Um but yeah, do you have any questions? Yes. Uh Oh, there's Yeah, there's a mic somewhere. Uh I don't know who has it. No. Uh it's not on the table. It It was. Yeah. Uh okay. Yeah, just just Yeah, just speak.

I'm curious about the efficiency of the ACIR compilation versus targeting something like Risk Zero. Um I know it's kind of efficient. I mean, you saw it in the example of how fast it it was to generate like the witness. And so, that was that was uh pretty fast, but that's not what's clogging the the whole process. Uh but as as for the benchmarks, no, we we we currently don't have the benchmarks. That's something that we Yeah, we're working on.

The expectation is substantially substantially faster than Zero. which is weird. Because because we're not going through the inner structure, particularly in the case it needs that if you it's much more efficient to directly express a completion like a strength of this different part of the 500 and I think it's 500. Um I think actually the way that I is in a doing it doing it did a talk on this I was doing a talk on this um in parallel about various forms of various gadgets.

What? Like the fact that you always need to have a little bit ahead with that machine and with that machine because of the scale of the network. Honestly, like Noir and RISC Zero are very very different execution environments because Noir is designed for privacy where you can search your locally on very resource intensive devices. So, it's worth going through the kind of the additional complexity of writing writing writing your skill programs in your directly in a in a language that can maximize efficiency. Whereas the RISC Zero um uh approach is to make it as easy as possible to write circuits by basically making it a RISC and increasing the need to construct a proof on very resource intensive devices, which is optimized

for hardware and that kind of thing. So, they're very very different environments. Thanks Zach. Uh any other questions? Sorry. It's fine. Who is talking in front? Yes, that's that's intent. But I actually tried like the basic Noir starter example and it didn't work, so I guess I did something wrong. But but yeah, it worked previously in the past previously in the past, yeah. I guess I'm yeah, kind of redundant. But it worked previously uh and so yeah, it's it's going to work on your phone. Actually, that's one of our goals. We need to fit everything in 1 gig of RAM.

Yeah, it's hard, right? Yeah, we're going to do it. Yeah. Any other questions? Yes. Is it was that a question? Yeah. What other kinds of backends do you do you support? I mean, do you and yeah, do you do support like say R1CS based backends? Um yeah, we had a version we had to ACVM for Merlin that you can you could use that and and R1CS I believe.

Um but I'm not entirely sure if it works currently because I've been making a lot of changes to the to the Sierra as well. But we support Groth and obviously we support Halo 2 which is kind of a new and I think it's not worth it. I mean, you get you get like the simplicity of Noir but then you Yeah, it's it it don't get the same speeds as just writing directly in Halo 2. Um and and I think that's it for now. We're working with other teams to to implement other backends. So, if you have if you have an idea of of a backend that would be cool to to to support just talk to me in the end and yeah.

It's it's not difficult basically just just need to write the ACVM and you actually have I believe some kind of a starter or boiler plate or something for for the ACVM. And yeah, I just need to write this translation thing. Any other questions? Cool. No questions.

Thank you, Jose. Thank you.