New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Best Mina application or library built using Protokit - ETHOnline 2024

ETHGlobalWed, Oct 9, 2024, 12:00 AM

Join us for a workshop with Matej sima titled, "Best Mina application or library built using Protokit " This workshop is part of ETHOnline 2024, an async hackathon that takes place from Aug 23 – Sept 13, 2024. ----------------- Follow us: https://x.com/ethglobal Check us out: https://ethglobal.com/ Email us at: hello@ethglobal.com

Transcript

let's get started so um Welcome to our Workshop introduction to protok kit today we'll be talking about how you can start building privacy enabled blockchains using a typescript cdsl for those of you who don't follow us yet on Twitter um you can see the handle um at the very start of the slide you can also join our Discord server to keep up with the development work or just head over to our website to to learn more about prodoc um this Workshop is going to take roughly one hour to complete we have around 30 slides of various content and chapters and we also have a live coding session at the end um using all the knowledge that we have obtained through the workshop um plus I'll stop every now and then um to give you room to ask questions so please leave your questions in the chat um I let Rafael collect um let's say the most important ones and we'll stop every now and then to answer these so let's get started with the first chapter um the first chapter is called from zero to ZK hero um and it will contain all the basics that you might need to start building zero knowledge applications so um first question is you know what is a ZK proof right um ZK proof is a mathematical proof of computation using inputs public or private uh that results in a publicly available output so it might include the public output too we just said that and what kind of computation can you mathematically prove so it could be various sour of computation uh you can prove that you have verified the signature using the correct public key um you could do a Merle tree proof or a Merle tree inclusion um and many more other kinds of computations you can do like addition multiplication and bunch of other stuff um within a ZK proof so to compute a proof you first need to start with a proof system um the proof system that we are using um in everything that we built is called kimchi and it's the same proof system that powers the Minas L1 um to obtain a proof you first need to execute something that we call a circuit and a circuit is basically a set of constraints or it's basically the code that you are using um which will be used to create the proof so like if you want to do your addition you will write your code inside of a circuit and once you run your code or run your circuit you will uh be given approved by the Pro system so um executing the circuit to receive a proove is one thing uh but before you can do that you have to compile the circuit to get uh two kinds of artifacts so you need a prover key to be able to run the circuit and generate proofs and you also need a verifier key or a verification key which will allow you to verify proofs one important thing to mention here is that that uh proving takes much longer than verifying so once you run an expensive computation within your circuit you can verify very quickly and very cheaply um so yeah that's what we just said um so what's the zero knowledge part of of of proving something of proving some computation it's the private inputs so the proof does not contain um in any publicly accessible form the private inputs that were used are as an input into your let's say calculation or into your circuit function so that allows you to prove that you have done a computation on top of a private input that is forgotten and never exported and that resulted into a certain public output um you can learn more either by like Googling stuff about Z know proof so there's a Wikipedia link and there's also a link for for something called the Mina book where you can learn more about the proof system itself um to write circuits um you first need some form of like a proof system language um what we use is a library called OJs OJs is effectively um a ZK DSL for writing circuits and the code snippet that you see right now is um basically a snippet that shows you how to write a very simple counter circuit so first you have to install OJs then you have to exp um import the experimental namespace and on the experiment namespace you will find something called the ZK program and the ZK program allows you to define a circuit so our circuit is going to be called counter so we'll just save it in a variable and let's go through the structure of the circuit or the program so every ZK program has a public input and a public output you can omit both of these you don't actually have to use them but both of them are super valuable when constructing a circuit so um apart from public inputs and outputs um every program can have multiple different methods and our program only has one method called an increment which will be used to increment the counter that we will work with every method can additionally also have different private inputs these are the inputs that will not be publicly available as part of the proof and our increment method contains two private inputs so um let's talk a bit more about what does the circuit actually do so the circuit inputs and out puts a field a field is the the most primitive or the simplest type of the kimchi Pro System um it's 256 bits uh large and it allows us to store multiple you know different types of data like for example hashes right so the buildin hashing Library uh once you create a hash it results into a single field so what do we want to achieve with this circuit so we want to write a circuit that allows someone to store a hidden number number or like a hash of a number and it allows you to increment the number only if you can guess the pre-image of the hash of that original number so let's go through the codes to make it more obvious um the public input would be the hash of the number that is the current state so let's say it's zero so that would be the hash of zero then we would have a and b a being the real value of the secret that you're providing as a private input um testing to the fact that you actually know the value and B would be the value by which you want to increment the number within the circuit prove that you have incremented the number by the given uh number B and as an output we would have another field which would be the hash of the new incremented number so this would create basically like a state machine where we can go from one secret number to another secret number in a proven way using a zero knowledge proof and a circuit so going line one line through the circuit we have this increment methods we have these inputs the public input and the private inputs the first thing that happens is that we have to verify if the user has provided the correct number as a private input so if the original state is zero um we would have to first turn it into fields and hash it to get the hash then we would have to assert that the hash calculated from the provided private input matches the public input which means that the user actually knows the number that he needs to like yes then we will increment the provided number and return back a hash of the incremented number so um let's just move to the next slide where I will show you how this program can be executed and how it can be used to prove State transitions from one number to another so um to run the circuit we first have to compile it we already discussed Pro and verifier keys so that's that's the easy part then we Define the initial state which should be a un 64 using the OJs SDK and that would be zero the public input the starting one or the initial state would be the hash of the state the number we want to increment by is going to be going to be one and then we just have to run the counter contract or not the contract sorry just the counter program so counter. increment we provide the public input so the state that we want to transition from then we provide the state in the unhashed format which is just zero and then the number that we want to increment by um by waiting for the proof system to create a proof of the execution of this increment method we receive a proof of increment or just a proof um the proof will contain then the public output which will be the hash of the State plus bu which which in our case is one so if we start with at zero the increment at one the public output of running that function function and the public output of the proof would be the hash of one because zero plus one and then a hash so um after we run that we can um extract the new public input or the new state from the proof and also update the state because we have just moved by one um now the important part is that after you run this computation here you can very cheaply verify it using the verification key so counter the verify with the provided Pro of increment will verify and as valid so it's like the simple round trip of how to write a circuit to be able to obtain a proof of some computation on inputs and outputs and then how to how to verify the proof so moving on um another important thing here is that um circuits or methods or proofs can be recursive because verification of a proof is just another computation that can be proven right so if you look at the original counter uh circuit which had the increment or the add method um we can add another private input which would be another proof from a different ZK program that can be verified within the counter ZK program so that could mean that in order to increment the counter not only you would have to know the original number that the counter is at but you would also have to provide let's say a credential proof that would attest that you are um eligible to even modify the counter or to provide the proof of a valid State transition so um recursive proes are probably the single most powerful primitive in the whole stack so um we'll be working with them throughout the workshop pretty extensively so um how is this helpful for blockchains like what kind of benefits do we have if we try to architect blockchains using Zer knowledge proofs so we know that blockchain is basically just like a distributed database with a consensus and it's like a transactional database in effect so how does a traditional like round reper transaction look like so users signed transactions which authorize their intent to like perform a certain action on the chain and then notes or blog producers execute these transactions to change the state on the Chain itself um these transactions are then bundled into a block executed you have state transitions coming out of them and then you have the new state of the chain after the blog has been produced um if you want to verify the block you have to rerun all of the transactions this is the case for basically um any non recursive proof blockchain that is out there um okay so what does this mean for the network itself it means that anyone who wants to run a node needs to meet certain relatively High Hardware requirements in order to be able to verify blocks um this makes it more and more difficult to decentralize the chain since the entry barrier is pretty high for people to run notes um with Mina the case is however um quite a bit different um what Mina does it takes uh it turns or like it turns the whole block creation process into a huge Z circuit or actually multiple different Z circuits um and these block proofs are then recursively composed to basically so what this means is that since all of the block production is a series of recursive circuits it means that uh the barrier of entry for running a note gets lower and lower because to verify a block you don't have to reexecute the transactions again you can just verify the proof provided by the block producer that uh with like certainty pretty much tells you that the transactions have been included correctly and that the block is valid so you don't have to execute transactions again you just have to verify a a block proof and a consensus proof and probably a bunch of other proofs um and you have then um the latest state so yeah blog is now a single recursive proof which is really amazing for multiple reasons um all right so um you can find more information in the protocol architecture I'll share the slides afterwards so you can find all the links um let's talk about how do smart contracts work work on the Minas native L1 so we already know that the L1 itself is basically like a huge recursive set of proofs so to verify the latest State you just need a single proof now let's take a look at how does it affect the smart contract design and what can you do with the L1 smart contract so um smart contracts Oma are built using the same1 JS Library as the ZK programs that we have seen before um there's a smart contract class that you can use and people often refer to these as c apps um smart contract is effectively just again another circuit that can produce a proof of its own execution it is executed not on chain like you would normally have like in an ebm model but instead it is executed of chain since we can then verify the proof of its execution on the Chain without having to execute it again um so before I've said that originally transactions would be assigned intent that would tell the node the user is trying to um execute let's say a smart contract method here is different um the user executes the smart contract themselves in the browser of chain and send the pro of execution to the chain itself okay so um since the node now doesn't know which code to execute on behalf of the user um it is sufficient that the note only receives a list of called count soal like account updates which are effectively the state transitions for the chain um and these come authorized by the proof of the execution of the smart contract so you execute a smart contract you generate a proof that you have executed it correctly and that execution results into account updates or state Transitions and these are authorized by the proofs and then sent to the chain to be applied to the chain State all right um they can also be authorized by signature so not just deplo um the blog producer order chain then verifies the proofs and updates the chain State we just discussed that and all of this is then recursively bundled into a single block proof so out of all of these recursive proofs you end up with a single block proof um and you can carry on with your day so it's really amazing um however there are also like U downsides to this approach so um running all the computation on the clients effectively results into uh race conditions because these clients are not aware of each other and they have no way of organizing of the chain so um let's take a look at how you would Implement a smart contract um using OJs so the example we're using is the same as the one that we have used for the ZK program uh but this time it's going to be a smart contract and the public input that we have used before is going to be saved on chain as part of the smart contract logic so we Define a class called counter it extends the fire contract class then we have to Define some storage that will be stored on chain keep in mind that you can only store eight times 256 bits of storage which means eight Fields worth of storage so this contract is only using one so for this example it's completely fine and it will work uh just okay so what we are storing on the Chain using this decorator and this public variable or the public property of the class we call it commitment and it's just going to for a single field then we will have an increment method that will accept two private inputs A and B same as the ZK program um the state that is stored on chain will become the public input into our smart contract um the business logic is identical to the ZK program so we first hash the input that you are supposed to know then we fetch the onchain state and um create something called the precondition which we will explain later um and then we make sure that the calculated hash matches the onchain commitment if it doesn't we throw an error which prevents the proof from being created um then we increment the numbers again A plus b and we create an incremented commitment and we update the onchain state with the incremented commitment so um I want to talk a bit more about preconditions and what exactly do they mean so when your smart contract runs off chain in your browser on your client it has to fetch the onchain state and then the proof that is Created from calling the increment method has to carry public input or output doesn't matter in this case um basically telling the chain when it goes to verify the proof which onchain state you have used for your transaction so when then there's two users creating the same proof using the same onchain state one of them one of their transactions gets in first it will invalidate the second proof because both of these proofs were based on the same initial state which is no longer valid so that is a precondition it is an additional validation for your offchain proof um so let's see how we would run this smart contract so you would just create a new instance pointing to an address of the deploy contract then you would do a Mina transaction by calling counter. increment with the number one parameter is missing here doesn't matter um and this call would then create a series of account updates as we have discussed before and this will be authorized by approve we'll create a state update that will change the commitment to the incremented commitment and we'll also have the original commitment that we have used in the computation as a precondition and it will tell the chain that this account update is meant for the address of our smart contract so when the chain goes to process that address it knows the verification key of our Circuit of the smart contract and can verify the authorization of the account update and apply all of the things listed in the account update to the chain State um so you have to prove the transaction that is where the authorization of the proof is added to the account updates and then you of course have to send it to the not so that's like the tldr on like ZK programs and SP contracts and let's take a brief look at a diagram of like a life cycle of a transaction on a smart contract so we start the life cycle by Alice executing the smart contract in the transaction API uh she provides the parameters needed for the contract execution the contract produces a list of account updates then it authorizes them by proving the counter not increment method within the Pro system and then sends the transaction to the chain so and when the chain eventually goes to Prive block with this transaction and many others it will do the following so it starts at initial chain state where the um commitment was I know commitment a then it goes to apply the account updates it checks if the account updates are authorized by verifying the proofs associated with the Circuit of the SP contract then if the proof is not valid um it throws away the account updates and the transaction is reverted if the proof is valid it proceeds with checking the prec conditions so it checks if the precondition the fact that we have used the initial commitment value to calculate this proof matches the onchain state so if the initial State matches the commitment we have used to calculate the proof then the precondition will be considered valid and then the state will be uh State updates will be applied and we will end up at a resulting state so in our case we go from commitment a to Commitment B by proving that the spart contract is really meant to create this kind of a state transition and then the chain applying that St transition to the onchain state okay um let's talk about key value storage in fire contracts so far we've only seen a state that stores a single field we can use eight of those but this is um essentially not enough if you want to have a more complex application that stores like let's say user deposits in a key value storage so the following syntax is uh not possible with L one SP contracts you cannot just Define a key and a value type and then just store multiple values on the Chain itself um this is due to like multiple reasons like probably the main reason is that every circuit calculation or computation has to be fixed size so users cannot just arbitrarily Define um any storage shapes that they want right so yeah um so this is not possible so what can we do about it like how can we build apps that have more States than uh possible out of the box so um instead of storing like a key value map on chain we can store a single commitment to a rud hash of a miracle tree which fits into a single field that would look like this so let's explain a bit more about what a mar 3 is so oh yeah here we go wrong slide so what is a Tre so Merle tree is a data structure that allows us to cryptog cryptographically verify that a certain Le is part of the inter structure so imagine that you have a huge database full of key value records and you want to do some computation on top of a single Row in the database so the row in this case would be the leave and to verify the Integrity of the data that the lead is really part of the database of your table or of your tree um you have to do what is called a mer Pro which means going from this Le and calculating the root through cryptographic hashing to ensure that um the data that you are using is really part of that uh of the three structure and the root is the commitment that we are storing on the Chain um so let's move on um the simplest way to use Merkle trees in my opinion is uh what's called a Merkle map it's an API provided by 1js so all Merk tree leaves can be identified by an index um if you use a Merk tree with a sufficient depth of 256 it means that there's going to be two to the power of 256 leaves which is like um a lot um I mean by single l i really mean a lot like it's a huge number um of all the records that you can have in your key value storage so thanks to the depth of the tree it means that the size of the index or the amount of the leaves will be from 0 to 2 to the power of 2.6 and this means that the index can be represented by a field because uh field has the same like range of values pretty much in binary um so this allows us to treat the tree like a key value storage where the key can be a field the value can be a field and the root will also be a field um and that's the merco map so here's how you can use the merco map so first you have to create a new instance of the mer map then Define a key and a value which both have to be filled um you can take any data type in sjs and turn it into an array of fields which will then allow you to Hash that and you will arrive at a single field so we do it for both of our key and the value and we can then set that to the merom map so the mer map will now be a tree of hashes of our values which we will be able to find by an index or a key um to prove that a certain value in a key are part of the of the tree we have to do it through a witness so we can get a mer witness and then using the real value that's supposed to be stored under um that index we can calculate the root hash so if you remember going back to Here by providing the value at the Le you uh and receiving this value and this value you can then compute the first green note and then using this note and this note you can then compute the root which tells you that you are using the correct value of for delete so going back to here um computed root and then computed key um which we can then use for our proving so um let's try to write a smart contract that uses a mer map based storage um for storing user counters right so we want to have a contract which allows us to store a counter for a specific public key and then incremented as we uh see fit so um we Define a counter's commitment this is a onchain State field that will store the root hash of our counter's uh Mer tree or mer M and a single increment method that tells us for which public key we want to increment and by what value keeping in mind that those are like private inputs again so first we have to uh do the precondition then where we uh get the State and then we assert that it equals the on chain State that's called the precondition then we have to turn these data types into something more compatible so we have to turn into single fields we have this helper that I've just used here but it does the hashing that we've seen before so the key for the public key will be a hash of the public key then uh we want to get the current counter for the user um and we do that for the specific key of like which is the public key um and that gives us again another abstract helper method very is for to say of the this example that will give us the actual value of the counter which would be zero for the first run and then a witness that points to that counter in the M tree so we have the value and the witness now we have to take the witness and hash representation of the real value to calculate the root hash of the tree and to calculate the key that the value belongs for according to the witness if the counter commitment again the mistake here should be the counter computed counter commitment matches the uh counter commitment that's stored on chain that means that the counter value that we have received as a private input uh right here is valid and we can trust it value um we have to do the same for the key and the computed key to make sure that the witness was really for the key that we are actually meant to be using so that's the publicly provided by the us um that's how do you validate data coming from a tree into your smart contract and in the second part we will take a look at how do you write data to the tree so let's move on um updating the tree data so um this is a continuation of the increment method so we will take the original counter value incremented by the number that we have provided by the user that will give us the new counter and then we will use the same witness to compute a new using the new value right so before we used the old value that was supposed to be in the tree that gave us the same room so we could verify the Integrity of the data and if you want to upgrade or sorry if you want to write to the same Le we will just use the same witness calculate the new root hash using the new value that's supposed to be in the tree and then we will take the new calculated commitment and we will set it as on chain State um Rafel do we have any questions in the in the meantime um you can start it basically anywhere you want so one of the first things that um like I've tried to build in the ecosystem was an offchain storage Library um we will go through explaining why that might be difficult or not possible to use offchain storage libraries um in the next slides okay so let's move on any other questions I assume not okay so um let's build on top of what ston was asking and let's take a look at the design limitations of these approach of using merries for data together with smart contracts so we know that users will execute smart contracts on the client side um independently of other clients we know that this leads to preconditions poting to the rootead of the tree we've discussed it just now um and this means that if there are two users transferring at the same time their preconditions will be the same their preconditions will be identical so this means that when the chain the1 goes to process these two user transactions one will invalidate the other so the first one that succeeds will update the own chain State and when the second one is being processed it will have a stale precondition pointing to the old on chain state so this makes it pretty impossible to achieve any meaningful concurrency if you write your smart contracts in the way that we have seen in the examples so far um so yeah um we just discussed this how the second transaction is invalidated and we also have a diagram that shows you how this actually happens right so we have this all happens on the client we have Alice that is executing counters of increment um then the increment method uh pulls in the actual data and the witness from some form of an offchain storage could be an API could be some distributed Network like we wrote libraries before for that um before we started writing Proto kit so um we have some experience there um this produces again account updates and the account update will try to update the chain state to a new rash and it will also have a precondition to the current onchain rud has commitment and uh the red part the current R commitment will match the current pre-state um but after the first transaction is created and if you have two in parallel um the first one will set it to the new Ro hash therefore the second precondition second transaction precondition will no longer be valid making the transaction fails um creating concurrency issues so um that was like the tldr on on DK program and spar contract um I I hope you guys went from zero to DK hero in the in the in the short span of time and now we can move forward with the actual subject of the workshop which is U trying to build a private airdrop on Mina so um what is a private airdrop and what kind of architecture do we need to to build one so we will be storing all addresses eligible uh we have a question yes yeah we will touch um touch upon that after the airdrop example so let's go through the airdrop example then explain how actions or sequence State could help you with that and what kind of bottle legs would you run into using actions and sequence State and then what else can we do to solve these things right so okay going back to the architecture um we will store all the all the addresses eligible for our in a Mer tree so we've just seen how to work with Merle trees how to read the WR data to them then um one important thing very important actually uh to keep this as private as possible is that everybody will receive the same amount of tokens from the aob if that wasn't the case then we would basically create a link between an address receiving a certain amount that information being public and then when the claiming happens uh you will be able to pinpoint which address receive the tokens based on the amount to the original address that was eligible so we want to avoid that therefore everybody gets the same amount um we will also need to build an air drop smart contract um which will have a claim method that will only give you tokens from the airdrop if you can prove that your address is part of the air drop parle tree we will also have to utilize something called the nullifiers to make sure that you don't claim twice by by proving two times in a row that your address is part of the air drop Merle tree we could just store the addresses that have already claimed in a separate mry but that would defeat the Privacy purpose of the private a therefore we use a nullifier which cannot be backtracked to the original address that was claiming from the airdrop so this effectively allows us to break the link between the address that was eligible and then the address that received the air tokens in the end so um just a little bit of a disclaimer um this architecture is pretty similar to tornado cache so um it's something that you definitely shouldn't be doing because of money laundering concerns um stuff like that um I also have to say that um we have limited time in the room and we will have to move to a separate room in about 10 minutes so I will share another Link in a moment okay so moving on we have this architecture we want to build a private air drop so how would the smart contract look like um we would define an aop smart contract it would store two fields on the Chain it would store the airr tree commitment which is a Mer tree that contains all the address eligible for the adrop then it would also store a root hash of the nullifier tree which contains all the nullifiers that have already been used to claim from the airdrop then we need a single method called claim that accepts several parameters so it accepts the ER of witness that's a witness that allows us to calculate that a certain address is really part of the ad tree then the nullifier which has been signed and created outside of the contract using the m assigner and then the nullifier witness which will allow us to prove that the nullifier has not yet been used as part of the nullifier tree so um we first have to get the onchain state and create conditions so we do it in the first two lines by using this fancy method called get aner equals um which allows us to save some uh some space and then we have to check if the user is part of the airdrop so we have to take the airdrop witness that we have for a specific key um which would be your index in the pr commitment and we compute a root and key using the value bulling through right so if you are in the tree the leave that's represented by your address will have a value one which is the field representation of the booing if it would have the value zero it means you are not in the tree so um we compute the HH and we also compute the key now we have to do two things so before we talk about verifying the nullifier let's talk about verifying these two variables um so we have the airdrop three commitment which is the old chain State coming from here and we have to assert that it equals the computed air drop tree commitment if we uh do this it makes sure that whatever address used to uh generate this witness was actually in the tree because you managed to arrive at the same root hash as is stored from chain hope that makes sense um if not um we can try to explain it more but um just let me know in the questions then we also have to check the computed a drop te and make sure that it asserts or it is equal we have to assert that it is equal to the public key used to generate the nullifier right so we take the nullifier we get the public key out of the nullifier we return it to field we hash it and we make sure that the witness is a witness for a key and that key is the public key that was used to generate a NF fire so we have all of these links um basically a testing that we can like it's basically a link in the proof or in the circuit the these variables um are arriving at the correct like the variables and the computation arrives at the correct values so um moving on forward with the logic so the second part of the smart contract would be um ensuring that the nullifier has not been used yet and then adding the nullifier to the threee of nullifiers to make sure that it cannot be double spaned again right so we have to update the nullifier so what can you do here so you take the nullifier witness which points to the uh nullifier that you are currently using we compute the roten key using the field zero so we are checking that the nullifier is not in the tri um we get the computed nullifier tree commitment which we will again compare with the onchain state to make sure that um the tree which we are proving against is the same as the tree or the state that is committed on chain um then we also have to take the nullifier key which is the unique message that can be like stored publicly and won't allow anyone to trace the key back to your actual address that you use to create a nullifier and we assert that it equals the computed nullifier key so uh we use the nullifier key as the index in the nulf stre um so this three lines of codes allowed us to check that the nullifier has not been used yet and now what we have to do is we have to write the nullifier to the tree and that's the last piece of the code in the contract so we take the same nullifier witness and we compute a new route using buing through we should have used field one or bulying FS here as well to to keep it consistent but uh at the end of the day it's the same result so um we use the nullifier key and it's nullifier witness to write bulling through to the leaf that is identified by the n Fire key and it gives us a new three commitment so effectively like I know I'm talking a lot about commitments Computing a Roots checking key or this or that but effectively it's just key value storage and you always have to uh take your data type turn it into a single field and then save that into the tree and store the actual value separately so in reality it's pretty straightforward um but you have to do all of this um fancy mat to verify the Integrity of the data and to prove the updates of the three data as well so we have the updated noi commitment and we can store it on chain using the account update uh State and then once we've done all of this and the proof didn't fail because the mulier has not been used yet and the airr inclusion ad inclusion was proven as well we can then uh use the send API of the smart contract to send Mina to the sender of the transaction and give him a fixed amount the important part here is that the address that will be used uh in the a witness and to sign the nullifier or to generate the nullifier will be different from the sender and this will allow us to send the tokens to the sender address without creating a link to the original address that was eligible for the in the first place um so yeah um that's it for smart contracts um before we move on any additional questions ra yeah so Gregor is saying that the nullifier has convenient methods for all of this stuff uh that is true the reason why I wrote the contracts like this uh is because I'm not familiar with them in the first place and the second place is because later down in the workshop we will go through um extracting this into a SE proof so um before we move on I'm going to ask everybody to hop into a separate uh into a different meeting room because we are running out of time in this one and I'll wait a couple of minutes after posting this link um for you to join the second meeting room all right see you there so um we have gone through the part of the workshop where we explain what the proof is what a circuit is how you can use circuits to create Spar contracts that can have their execution proven of chain uh we've seen a diagram how that relates to Min and L1 and how it is possible to verify this offchain computation of this fire contracts and uh wait uh one moment I think I have a mix up in my slides okay wait is it being recorded yes it is being recorded and we will update the recording afterwards wait so we've been through the design limitations we've been through the airdrop okay so um let me just resume my screen sharing okay we're back so um I think it's now time to answer bandon's question so how do we like is there any building way on the to address the concurrency issues that we have been describing um yes there is um but before we talk about how you can address this I want to talk about like the general approach so the approach that we believe um everyone should be taken to address these concurrency issues and also the approach that the um official dogs of mina are suggesting is effectively to write your own rollups right so what would a rollup actually be it would be that instead of users running their um smart contracts of chain themselves the users would be effectively sending transactions or referred to as actions in the one protocol um and then someone would roll all of these actions up which would effectively create like a rollup block so um the el1 already has like Primitives for like these microps called sequence State actions and the reducer API um so the next chapter we will talk about Proto kit Proto kit is a framework that allows you to use the same Concepts as sequence State actions and a reducer and it provides you a very convenient API to write your circuits so that they can be rolled up using an approach like sequence State and a reducer so we have these concurrency issues we've seen a far Contra and how it get implemented now we need to learn how to implement circuits in a way that we can roll them up into individual blocks and get them settled on the L1 so um time to talk about proit um the CR of the of the workshop so uh prot is a protocol development framework for privacy enabled application chains also referred to as ZK rollups or ck validium or like depends on how you deploy them um to get started with prod um you just have to run the simple command below here uh we won't do that now um we'll walk through the workshop um and then we'll do a live uh coding session afterwards so what is protet um prot is a typescript based framework for building ZK chains ZK rollups application chains uh you name it it's not another ZK evm based ZK rollup instead it uses a Custom Tailor ckvm that is like privacy friendly so sorry um it offers a hybrid execution model um that allows both off and onchain execution off execution means the same as we've seen with smart contracts before it allows you to consume client side Z knowledge proofs same way as the smart contracts on the L1 um chains running with the prod framework also get the direct benefit of end to end provent execution so it means when sequencer or the node operator runs your chain and processes user transactions the sequence operator does not have any room for any malicious activity because to produce a valid block proof at the end he has to execute all the circuits that create your chain correctly with no room for anything malicious um also everything that you build with proit is going to be completely customizable and modular so it means that if you don't like a certain part of the system um you can replace it very very easily um one of the main design goals of the framework was to have virtually no learning curve um but you should still be paying attention because there's going to be a lot of interesting stuff um so what I mean by no learning curve um can be expressed very simply so lot of the apis are similar to the spart contuct apis and it's using the same OJs DSL so it means that if you've been using circuits or supp contracts before transitioning to prot kit and getting rid of the concurrency issues by writing recursive rollups instead of just simple smart contract should be fa simple so um we want to build our like you want to build your own z r right you have your smart contract you have your concurrency issues and you want to address those somehow so you can build a recursive z r that's going to be a series of recursive circuits that prove that transaction or as Brandon was asking action execution and the state positions Behind these uh behind the business logic that's being executed so a state transition is effectively merry operations so um we already know that the L1 offers sequence State and actions to help you build ZK rups but you still have to write your own circuits and even if L1 didn't offer sequence dat actions as part of protocol um you would still have to like Rite your own man pool so um I will just detour a little bit to explain how this works so with prot kit we are not using sequence dat and actions directly but we are using the same identical Concepts behind sequence dat and actions which ensure um basically enter and pro and execution of all of your actions without like any uh any break in the system so it means that if a user dispatches an action and then there's a bundle of actions that means there are at least 10 transactions that have to be executed when the sequencer goes and executes the bundle of the transactions the sequencer cannot skip transaction transactions at their own will which is the same concept as sequence a effectively is um another reason for us to go with a private manol over sequence State and actions is that just to dispatch an action aspir of the sequence State on DL one uh you would still have to create a proof um don't quote me on that like we have Gregor and Brandon here who can tell us more about it but in my experience or in my understanding just to dispatch an action you have to create a proof which is much more time and resource intensive uh than just signing a transaction as you would in our private mle um it it still doesn't mean that you cannot use sequence dates and actions if you want you can write a mle pend or a mle module for Proto kit uh that would use sequence data in actions directly and you wouldn't have to use our private signature based mle anymore okay so prot enables you to build your knowledge interoperable and privacy preserving application chains with a minimum loing curve right you already know that so you can roll your own ZK rollup in a few lines of code and uh it's also important to mention that these ZK rollups are effectively nothing more than a super set of ZK apps so it means that you get the opin Privacy features with public onchain execution that allows you to deliver the best possible experience so with smart contracts the Privacy is pretty much um always there let's say um and you don't have any room for onch execution so there's no onchain execution in the contract but with a prot chain you get both you get both the offchain execution with privacy and onchain public execution this allows us to uh combine the business logic in a way that makes the most sense to get the most out of the user experience so um what is a prot z up or an application chain made of um it consists of Fran time which is a series of circuits that Define your application logic this could be auction dexes balances investing modules or whatever else that your application might require in terms of business logic then we have the protocol circuits so that's the underlying virtual machine the block production transaction fees that are handled here uh account State stuff like nonis all of that is handled under the protocol and then we have the sequencer which is like the note or the server that has like offers mle Services um and orchestrates all the blog production and handles most importantly also the settlement to the L1 so once transactions are processed block proofs are created they have to be settled to the1 but we'll have a diagram explaining that in in more detail so yeah also the L1 settlement contract okay um what kind of features can you expect if you use prot kit so um main focus having a supercharged developer experience you just have to know typescripts and a little bit of OJs here and there um you can write and use reusable modules um you can use open source libraries that offer protoc modules like for example we wrote a DEX that Dex is open source so you can take the balances module uh which is effectively The Ledger for the chain um from our deex and use it as part of your project uh with no limitations um also the chains build with prodid will have no data Ras conditions unless you choose to specifically engineer your system in a way that would recreate the uh issue with preconditions known from the1 right so if you want you can choose to do that since this is just the super set of zabs but um the main purpose of the tool was to allow you to build in a way that will not have race conditions um the onchain storage uh that we will see in a moment is effectively bottomless because we use the largest Merkel tree possible and the amount of records that you can store there um is not even worth mentioning because before you run out of available records you will probably run out of memory anyways or like the number is infinitely huge so you still get your offchain privacy because you can create proofs from circuits on the client side same as with ZK apps and send these as Arguments for onchain transactions to be executed in a sequence manner on chain um you get to focus on your business logic you don't have to do all the heavy lifting so theer operations that you have seen for example to verify data or to roll your own rollups um you wouldn't have to do that anymore because we wrote all the circuits and all the Machinery behind the scenes all you have to do is just focus on your business logic and write your run time um proty chains or proty transactions are compatible with user valids in the ecosystem because we rely on features from the mean assigner directly um as we said before it's not an another Z KVM but it's a sync ZK VM and I hope I pronounced it correctly um I've been saying this for a while now but you can reimplement the zkf preconditions in your runtime if you want to but out of the box um you can just treat proty chains like you would treat development on another like on any other evm like ecosystem that you are already familiar with so this also makes it super easier for new covers to build because they don't have to learn how smart contracts or zaps work because they are super specific to to to dl1 um and instead they canuse their existing Knowledge from evm like ecosystems to start building the protocy um since this is a super set of ZK apps um and you need some specific features that are not yet available in the ZK apps on the L1 you can um completely customize the behavior of your own chain therefore you can get access to Features faster than let's say the L1 would be able to iterate on because the L1 Bears a lot more responsibility towards the whole ecosystem and features specific to your app might not be necessary for everybody else and therefore belong on your app only so you can do that with prot um features that will be available um soon so um the chains need to be interoperable with each other and also with d L1 um like varing degrees of security guarantees compared to the ux available and you also need data availability unless uh you want to stay a validium instead of a rollup so we have plans to address all of these um but don't tell anyone just yet so moving on um how does the protate architecture look like or what is the life cycle of a transaction so before we had the same diagram for smart contract and now we'll take a look at how to basically achieve the same things as before but with prodoc so the only thing that needs to happen on the client side is that Ellis needs to sign a transaction she doesn't need to prove anything on the client which makes it um basically faster right so we've discussed before that even if you want to use sequence state in actions you still have to prove the change to the sequence state so um Ellis creates a transaction specify which runtime module and Method and what arguments she wants to use that is signed and sent to the ZK rollup or to the sequencer so it's just a simple transaction then um the sequencer takes all the transactions and executes them by running the runtime uh method which is which means that it creates a proof of the runtime method execution that also produces State transitions similar to account update that we have seen before and then these data transitions are applied by the protocol so the protocol writes the Merkle tree data updates and then the block proof takes together the proof of the runtime execution and the proof of applying all the state transitions merges them together and creates a block proof this happens for all the transactions until we have a final block proof that block proof is then settled on the Mina L1 so every produ chain will have a smart contract running on the L1 which will receive block proofs only from your rollup which means that you can settle to the Mina L1 so like what does settlement mean like you could run it without the L1 that would be like a sovereign BL up um that unfortunately doesn't have much security because you have like a centralized sequencer on a Rec model um and the only thing that you can rely on in this case with a ZK souring rollup would be that the execution would be correct right because there's a circuit and everyone can verify the block prooof this is effectively how how the Mina L1 works plus you also have consensus uh which makes it like a full uh proper L1 so since the your Z doesn't have consensus you need settlement instead and you reuse the consensus of the L1 to settle your block proofs right here so there's a block proof created that tells the chain that we are transitioning from State a to State B on the Rob and that is sent to the L1 uh do we have any questions in the meantime Rafael all right let's move on okay so um before we were writing smart contracts in circuits in in protate you won't write smart contracts anymore you will write runtime modules which will be the bread and but of your chain so um users cannot just deploy smart contracts on their own to your chain your chain is built for a specific purpose a specific application and therefore the business logic is baked into the core run time of the chain itself so let's take a look at example at an example of how you could write a run time to handle balances and Native and thirdparty token transfers in your chain so you would write a class called balances that would extend the provided class runtime module don't don't worry about the unknown this is config related thing and since we are not using any config for the runtime we're just going to leave it empty as is you we also have to decorate it with a runtime module decorator that does a bunch of like interesting things behind the scenes that we might explain at another Workshop then um same as on the smart contracts you have uh you have to Define some state with the difference that a perate run time is not limited to PID field so and you can also use key value storage we call that a map so we want to store a map of balances it's going to be a state map where the key is going to be a public key of the user and the balance is going to be a un 64 then we need to Define methods that users can call in transactions we will label them with the runtime method decorator and we'll just call this function transfer um what is important to not here um if you remember the previous diagram this function is going to be triggered by user signing a transaction and execute it on the sequencer so there's not going to be any congruency issues because the sequencer will order all the user transactions and execute them and the save transitions in an ordered or a sequenced manner so um what does the transfer method do it transfers from a public key to a public key a certain amount um so how would the implementation look like so first we have to optain the from and the two balance which is do that using the state map get API which is relatively straightforward any calls to the state API will produce State transitions behind the scenes which are like quasi equivalent to the account update then we have to check like some Sello transfer logic we have to check if the FR from balance of that from Key the front balance is greater or equal than the amount being sent we check that here this gives us a booing from balance is sufficient one important thing here is to note that we cannot uh use assert apis from OJs because we don't want this onchain execution to fail forcefully we want to fail it in a like a silent manner that can be done processed by the protocol so we use a custom assert API that's available from uh from protoc So You assert that the front balance is sufficient and if it's not you will throw an error that the balance is insufficient this creates a flag behind the scene that tells the protocol that the method was not executed correctly and the state transitions for it should be discarded but the transaction will still be included in the block but the status will be that it failed um this is something that we've seen for example Stark net only at recent um or stare I don't know um like they were not able to even Pro like process failed transactions before so um then we have to decrease the balance from by the amount that is being sent and we have to set it to the uh chain API there's a little error here let me just um fix that real quick so when you are setting the balance you have to set it for an address and then a value so it would actually look like this uh yes questions Rafa do we have any questions sure sure let me let me do it just really quickly so um we use a dependency injection framework called te range to orchestrate um the chain and the dependencies and all the modules that come come with it runtime module makes the class injectable as part of the dependency injection framework um that's like the main feature that it does um the state decorator I'm not sure if you asked about that but so the state decorator basically helps us identify which index in the global Merle tree State uh the balances are stored under so if you store a balance for the from public key the the path or the index would be created from balances dot balances do the from address and that is what we would compute the LEF index in the global tree state from um hope that makes sense and then the runtime method is probably the most veros like internally veros part of code in the entire system um if we think about like the module API itself um and what it actually does it wraps your function into another function that ensures that the protocol execution was correct so um you can imagine your function being nested into another parent or a higher orderer function that also checks your execution status extracts all the state transitions uh creates the public outputs for the underlying ZK circuits and all the other things that you don't want to care about as a developer unless you really want to go down to that level like of of the tooling itself so this is pretty much a heavy lift from the shoulders of the users so that they can focus on only writing the piece of logic That Matters to them and they don't have to carry about the protocol behind the scenes um is there any other questions Rafel yeah I mean don't have that much time I don't know how long people want to stay um tldr um you get on execution you don't get that with SM contract that's like the main selling point um from the slides before all right uh let's move on so writing your own run time so now you wrote runtime module now how the hell do you create a rollup out of it how the hell do you create an app chain out of it so writing a run time now testing a run time right so if you want to execute a runtime Let's uh first do a little bit of a setup so we first create some keys for alies and Bob so that we can do the transfer from and to then we create a testing app chain from runtime modules and the only thing we have to do is pass in the balances class that we have created with a config that's empty because we are currently not providing any config for the module so now we have an app chain and we can start it very simple one line of code and we also can set a signer for the app chain API which will be Alis um this will be obvious in the next uh slide where we have to create a transaction to the transfer method of the balances runtime module we first do that by extracting or resolving the balances runtime module this gives us an instance of the balances runtime module then we make a transaction using the transaction API uh using Ellis as the sender and we make a transfer using balance is that transfer from Alis to bul for a certain amount of tokens now we have to sign the transaction and send it and then in the test what you would have to do is to produce a block this basically triggers the block production pipeline in your tests as part of your testing app chain uh processes the transactions that you have signed and sent uh processes all of the state Transitions and gives you a block proof even though it's just a simulated block proof because in your tests you are not running in appr proove remote because it will be slow etc etc um so you eventually produce a block now the last step would be to actually take a look at the onchain state and make sure that pop has really received the balance that we have transferred as part of our logic so you can use the query API for that so app chain query we are querying the runtime State the balance is module the balance is state map uh uh the Balan state map and we are getting an entry from the key value of the state map uh identified by the B's public key and if our transfer was successful and the blog was produced correctly uh the balance of Bob that we would receive would be an instance of un 64 data type holding 100 right um to be able to actually do this you would have to mean the balance for Alice first otherwise the transaction would fail but like to keep things simple uh we've only demonstrated how the transfer would work all right so um the last part of the workshop um I believe we have about 50 minutes left so we might not do like a live coding session but I can walk you through how the airdrop code that we have seen for the SM contract would look like in a product at rant time what kind of components would you have to build for that and how the test would look like and how the overall developer experience would be so um assuming we don't have any other questions Rafa um okay so let me just stop sharing and prepare the workshop material okay so going to re share my screen real quick entire screen this one okay so I hope you can guys um see my screen let me know if I should like zoom in or anything okay so um I'm inan my editor um you see the workshop repository you have two folders one 40 Workshop slides I'll share the link to the rep later so you can check it out yourself but the folder that we are after right now um would be the one which tells us how to build the same uh private air functionality as we've seen with the smart contract but with a protoid runtime and what kind of benefits would we get if we build this using protoid and um what kind of things would not work with the smart contract on its own so um the components that we will need for our runtime would be a balances runtime that allows us to Min a certain balance so when the user claims for the air drop we will me a balance for them the only thing that it does is the same as the balances example we've seen just now it gets the balance increments it by the amount that's necessary and it updates the user balance keep in mind that mint is not attacked with the Run onetime uh method decorator that makes it not publicly callable through a user transaction and it makes it only callable internally from other onetime modules which make sure that users are not meting freely as they see fit but uh based on some business logic that needs to be applied beforehand then we will also have a airdrop runtime module that will do a bunch of different things so it will store a commitment to the airdrop tree the same as we had in The Spar contract but this time it will not store a commitment to a nullifier tree instead it will store a key value state map of nullifiers and an indicator if they have been used or not so um the airdrop runtime module will do also one interesting thing and that's create a dependency to the balances module so if your testing app chain would have a runtime consisting of balances and airdrop it would enable the airdrop runtime module to inject the balances module and use it directly so we do that by the Constructor and that is why we have the runtime module decorator so we can use the dependency injection library and so on and so forth so um going through the methods like the first one that we would Implement would be uh set commitment what this does it tells the airdrop runtime which commitment or which airdrop tree boot has to use so um let's imagine that we wrote this class we wrote the uh onchain State for the commitment and then we wrote the method for setting the commitment now we would have to write a test for it right so let's move back to the test and see how a test for this would look like we don't need this um and we only need these two okay so before all of the tests will run we will have to again set up the testing app chain that will consist of the two runtime modules that we have built um and an empty config then we will set L as assigner start the app chain and resolve the runtime modules so that we can use them within our tests and within our transactions so the first thing you have to do is um set the commitment to the airdrop three root has so to do that we have to also Define the end drop tree we do that above in the test we create a new Merle map uh we create a new key using the alysis address and we update the merco map uh this is what Ste was asking before like where do you store the Merkle tree for the purpose of the test it lives only in the memory here um keep in mind that this is the airdrop tree that is not part of the on chain State uh we just use the commitment from it so uh we now have a map where Alis is stored and that indicates that Alis is eligible for the air drop and we also obtain a witness from that that's useful for later so um to set the commitment we get the root has out of the map where Ellis is already stored and we send the transaction sign and send it produce a block and then in the test we ensure that the commitment actually made it to the chain state by querying the runtime air drop commitment State and running an expect that ensures that the onchain commitment onchain meaning on the2 matches the root hash from the map that we are using so that would be the first test right now we have an runtime that stores a commitment so now we have to move on uh we have to move on to the implementation of the claim method so before in the smart contract we provided all the witnesses including the nullifier to the smart contract method itself because it was executed off chain however runtime methods as we already know are executed on Chain by the sequencer not on chain on the L1 but on chain on the L2 so we cannot uh tell the sequencer which ATS we are claiming for because that would uh break the purpose of the private airdrop and it would expose which address we are claiming for which is the only thing that we are trying to avoid by Design so instead to preserve the Privacy aspects the claim method will accept an airdrop proof the airdrop proof will do the exact same thing of verifying the nullifier and the Merkle proofs of the air drop tree of the chain on the client side in the browser it's going to be signed and sent as part part of the transaction to the sequencer and then it's going to be executed by the sequencer when the claim method runs and it's going to run all of these other additional uh business logic so um let's take a look at how the air drop proof is constructed first before we take a look at uh what else does the claim method do so our air drop program is really simple uh it results into an air drop proof and it has a single method called can claim that has two private inputs the Merle witness for the airdrop tree and the nullifier as before um as an output it has air drop public uh output which is the root hash that we have been able to calculate from the um air drop tree witness and it also has a nullifier key in the output so that we can then process the nullifier key on chain and store it in the state map of nullifiers in a sequenced way without having the same precondition issues as with the L1 smart contract so this is the pretty much the most important part and it should be like the key takeaway in terms of differences between smart contracts and runtime modules runtime modules allow you to overcome the uh uh the concurrency issues and the race conditions by moving part of the execution on chain where uh the state transitions that need to be sequential are done in a sequential manner by the sequencer so uh we have the root and then nullifier key and now let's take a look at the implementation of the ZK program so we know the private inputs are the witness to the air drop tree and then mif fire itself and it Returns the public output which we have just discussed so we take the nullifier this happens of chain and we take a look at the public key that was used to calculate a nullifier and we turn into fields and we hash it again this will create a single field which will be the key used um to calculate the root hash from the from the witness right so then we take the witness for the Ed drop tree we compute the rot and key expecting this address to have a bull tree value in the tree that gives us a root hash and a computed key so um we have to assert that the computed key from the witness or the key that identifies the Lea that the witness is created for is the same as the key derived from the nullifier public key so effectively effectively what this does even I like probably all complicated the explanation by a tenfold is that it creates a link by the witness being for specific leave which means being for a specific address and the nullifier being for a specific address this is very important um additionally it also verifies that the nullifier was created for specific purpose we do that by using a message that needs to be unique enough like for the test purposes it's very simple it's not unique at all um this would mean that as an application developer you are meant to create a nullifier that's uh using a message that's unique enough so you can prevent collisions with other applications by using the same message because then the nullifier could be misused or double spin for different purpose and you want to avoid that so the message needs to be unique not like in our test um we've computed The Roots we verified the key we verified the nullifier and now what we can return from the proof is the computed route to make sure that the proof was done on top of the correct witness and using the correct Merle Tre data and we also export the nullifier key so that we can break the link between the address used to calculate the uh Merle proof and uh the address that claims the funds in the end and we do that by connecting them basically by a nullifier which is something that cannot be back traced to the original address and will will be stored by the nullifier stream this nullifier here so this gives us n proof and the air drop proof has the public output of the root and the nullifier so uh going back to the run time and how does claiming work so you provide the air drop proof um this shouldn't be there obviously right um you verify the air drop proof because we know that verifying and another recursive proof is just another computation that needs to be verified then we get the commitment from the on chain State we make sure that we create a soft assertion so we don't assert equals we create the soft assertion and a soft failure potentially that the ER proof and its public input and the root that it contains equals the commitment and therefore matches the same tree as as it stored on chain if it doesn't you get this custom error um now we need to check if the nullifier has already been used so we take the nullifier key from the public output of the proof we try to get it from the nullifier state map and if we are able to assert that um the value for the nullifier is false and not true which means it hasn't been used um then we can continue if at this point we figure out that this nullifier has already been used we need to throw an error and that's why we have this assertion here so then um we if it wasn't used and the transaction didn't error out we will set the nullifier key to the nullifier state map to make sure that it cannot be like reused again which is you know what the logic above uh checks as well if you run this the second time using the same a proof using the same nullifier it would error out because the nullifier has already been used and that's only there also possible without like having to keep track of who the original U address was so um once you've completed all of these checks and you know that the user is eligible for the airdrop and the nul his nullifier hasn't been used yet uh you can mint the balance for the user and we do that by meting the balance for the center of the transaction which is hopefully a different address if you want to preserve privacy then the address that you're approving for and we will me you a th000 tokens um and that's pretty much it now we have to take a look at how it looks in the test and then um we can use the rest of the time to discuss um additional questions so um we've seen how setting the commitment works it was this test now we have to see how to construct the proof um how to create a nullifier so that we can make the transaction here so um we first have to create a test nullifier using the 0js API for a specific message signed by Alis um that's important so we have a nullifier for for Alice now we have to execute the can claim method of the circuit using the provided witness and the nullifier and we have to turn it into a mo proof so let's take a look at how that that looks so a mock proof um is going to return as an airdrop proof which is going to type check and be a valid proof for the airdrop program so it's just like syntactic sugar for for like testing purposes U that we can use to calculate the dami proof and then return an instance of the proof class that would contain the correct public output that we are using for testing so we don't actually have to run the proving we just have a mock proof and we can uh do the tests pretty fast so um we have the nullifier we have the proof now it's time to do the transaction so we send this mock proof to the uh air drop claim method and we we sign it and send it then we again produce a block and then we have to do some checks to see if the transaction was successful or not first we can check the transaction status to be true that is what we are expecting to to work then we can check if we have the stored nullifier and if it's if it's true or not if it was false it means that the nullifier wouldn't be stored now the value of the nullifier is true under the nullifier key so we know that the nullifier has been stored and then we have to check uh the balance for Ellis in this case because we are sending it to the same address as is in the airdrop P list which is not exactly what you want to be doing you should be uh you should be a separate address right but for testing purposes it is the same address so we check the balance of Ellis by looking for the runtime balances balances state for Ellis and that is 1,000 because the air runtime has transferred 1,000 tokens or actually minted 1,000 tokens for us as a result of the successful air drop claiming um and then we also have a test where we have a negative like a negative case where we try to claim using uh the same nullifier and the same air drop proof and this returns uh this results into a failed transaction where the error is that the nullifier has already been used um the nullifier still stays true and the balance doesn't change so that's pretty much it as far as the workshop goes I believe we uh exhausted the time precisely so if you have any questions um I would be more than happy to to answer

Automatic transcript — names and jargon may be misspelled.