Please note that zkApp programmability is not yet available on Mina Mainnet, but zkApps can now be deployed to Berkeley Testnet.
How zkApps Work
zkApps are written in TypeScript using the Mina zkApp CLI. In the upcoming section how to write a zkApp, we’ll go into detail about writing your first zkApp. For now, we’ll discuss how zkApps work.
A “zkApp” consists of two parts: 1) a smart contract and 2) an UI (user interface) for users to interact with it.
We use the term “smart contract” to refer to the code written with SnarkyJS (which will be introduced below).
We use the term “zkApp” to refer to the UI + the smart contract.
Zero-knowledge based smart contracts
Because zkApps are based on zero-knowledge proofs (zk-SNARKs), a zkApp developer writes what is called a “circuit”, which is the method from which a prover function and a corresponding verifier function are derived during the build process.
The prover function is the function which executes a smart contract’s custom logic.
The prover function runs in a user’s web browser as part of the zkApp. When interacting with a zkApp's UI, users will enter any data (e.g. “buy ABC for y price”) required as input to the prover function, which will then generate a zero-knowledge proof.
Both private inputs and public inputs represent data that must be provided to the prover function when it runs in the user’s web browser.
Private inputs are not needed again after that point. But public inputs must be also provided to the verifier function (to be introduced soon) when it runs on the Mina network, and as such should never be used for data that you want to remain private.
The verifier function is the function that validates whether a zero-knowledge proof successfully passes all the constraints defined in the prover function. This always runs quickly and efficiently irrespective of the prover function’s complexity.
Within the Mina network, Mina acts as the verifier and runs the verifier function. We’ll describe how this works soon.
Prover Function & Verification Key
When a zkApp developer writes their smart contract and runs
npm run build, the build process outputs
smart_contract.js. From this, you can run your prover function or generate a verification key, which you will need to run or deploy your smart contract, respectively.
The prover function runs in a user’s web browser.
The verification key lives on chain for a given zkApp account and is used by the Mina network to verify that a zero-knowledge proof has met all constraints defined in the prover. A verification key is required in order to create a zkApp account. We will describe this more below.
The next two sections will go into more detail about how the prover and verifier functions are used when a zkApp is deployed and when users interact with a zkApp.
Deploying a smart contract
To deploy a smart contract to the Mina network, the developer uses the Mina zkApp CLI. The deployment process sends a transaction containing the verification key to an address on the Mina blockchain.
When a Mina address contains a verification key, it acts as a zkApp account. Whereas a regular Mina account can receive any transactions, a zkApp account can only successfully receive transactions containing a proof that satisfies the verifier function. Any transactions that do not pass the verifier function will be rejected by the Mina network.
When you deploy to a new Mina address, the Mina Protocol will charge a 1 MINA fee for account creation. This is unrelated to zkapps and is to help prevent sybil or denial of service attacks.
Deploying a zkApp UI
Developers usually build a UI to allow users to interact with the smart contract.
Typically, this is a static website deployed to a host of the developer’s choosing. We recommend web hosts that offer a global CDN to ensure the best user experience.
Your website needs to contain the
smart_contract.js file that was generated when building your smart contract. On the how to write a zkApp page, we will go into more detail.
How users interact with a zkApp
To use a zkApp, users must install Auro wallet for Google Chrome. We anticipate other wallets to add support for zkapps in the future.
Auro is the only wallet that supports zkApp transactions currently. However, we plan to expand support for zkApps to other types of wallets (such as mobile wallets and desktop wallets) in the future.
After a zkApp is deployed to a host (e.g. mycoolzkapp.com), users can interact with it:
- User visits mycoolzkapp.com.
- User interacts with the zkApp and enters any data as required. (For example, if this were an automated market maker, the user might specify to “buy x amount of ABC at y price”.)
- The prover function in the zkApp will now generate a zero-knowledge proof locally given the data entered by the user. This data can be either private (which will never be seen by the blockchain) or public (which will be stored either on chain or off chain), depending on what the developer specified, as needed for a given use case. Additionally, a list of state updates to be created by this transaction is generated and is associated with this proof. (We refer to these as “events” and we’ll describe them in more detail further below.)
- User clicks “submit to chain” in the zkApp UI and their wallet (such as a browser extension wallet) will prompt them to confirm sending the transaction. The wallet signs the transaction containing the proof and associated description of state to update and sends it to the Mina blockchain.
- When the Mina network receives this transaction, it will verify that the proof successfully passes the verifier method listed on the zkApp account. If the network accepts this transaction, this indicates that this proof and the requested state changes are valid and, as such, are allowed to update the zkApp’s state.
How is state updated on chain
You may be wondering how the state on a zkApp account gets updated on chain. We glossed over that detail earlier to keep things simple.
When the prover function runs in a web browser, the smart contract outputs a proof and some associated data that we call “events”. This is sent as part of the transaction when sending a transaction to a zkApp address. These events are a plaintext description (in JSON) describing how to update the state on a zkApp account.
The integrity of these events is ensured by passing a hash of these events as a public input to the smart contract. They must be present and unmodified for the verification function to pass successfully when it runs on Mina. In this way, the Mina network can confirm the integrity of both the proof and the associated events which describe how to update the zkApp account’s state.
Two different types of state exist on Mina: on-chain state and off-chain state.
On-chain state describes state that lives on the Mina blockchain. Off-chain state describes state stored anywhere else--such as IPFS, etc.
Each zkApp account provides 8 fields of 32 bytes each of arbitrary storage. You may store anything here as long as it fits in the size provided.
If you anticipate your state to be larger than this, or if the state accumulates per user with your zkApp, then you’ll want to use off-chain state instead.
Support for off-chain state will be coming soon.
For larger data, you may want to consider storing the root of a Merkle tree (or similar data structure) within your zkApp’s on-chain storage that references additional off-chain state stored elsewhere, in a location of your choosing, such as IPFS.
When the zkApp runs in a user’s web browser, it may insert state to an external storage, such as IPFS. When the transaction is sent to the Mina network, if it accepts this zkApp transaction (i.e. this proof & state were valid so the updates are allowed), then the zkApp transaction would update the root of the Merkle tree that is stored on chain.
On the next page, we’ll dive into how to write a zkApp!