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 how to write a zkApp section, you learn the details about writing your first zkApp. But first, get started by learning how zkApps work.
A “zkApp” consists of two parts: 1) a smart contract and 2) a UI (user interface) for users to interact with it.
The term “smart contract” refers to the code written with SnarkyJS.
The term “zkApp” refers 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”. A circuit 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 that 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 enter any data (e.g. “buy ABC for y price”) required as input to the prover function, which then generates 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 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.
Prover Function & Verification Key
The zkApp developer writes smart contracts and then uses the
npm run build command. The build process outputs
smart_contract.js. From this, you can:
- Run your prover function to run your smart contract
- Generate a verification key to deploy your smart contract
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.
The next two sections 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 zkApp developer uses the Mina zkApp CLI. The deployment process sends a transaction that contains 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 that contain a proof that satisfies the verifier function. Any transactions that do not pass the verifier function are rejected by the Mina network.
When you deploy to a new Mina address, the Mina Protocol charges a 1 MINA fee for account creation. This fee is unrelated to zkAapps and helps to prevent Sybil or denial of service attacks.
Deploying a zkApp UI
zkApp developers usually build a UI to allow users to interact with the smart contract and then deploy this interactive UI as a static website. Choosing a host that offers a global content delivery network (CDN) ensures the best experience for all of your users.
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 generates a zero-knowledge proof locally using the data entered by the user. This data can be either private (which is never be seen by the blockchain) or public (which is 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 (called account updates) to be created by this transaction is generated and is associated with this proof.
- User clicks “submit to chain” in the zkApp UI and their wallet (such as a browser extension wallet) prompts them to confirm sending the transaction. The wallet signs the transaction that contains the proof and associated description of state to update and sends it to the Mina blockchain.
- When the Mina network receives this transaction, it verifies 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 state is updated on chain
Now you have learned enough to wonder how the state on a zkApp account gets updated on chain.
When the prover function runs in a web browser, the smart contract outputs a proof and some associated data called "account updates" that are sent as part of the transaction when sending a transaction to a zkApp address. The account updates are a JSON plaintext description that describe how to update the state on a zkApp account.
The integrity of these account updates is ensured by passing a hash of the account updates as a public input to the smart contract. The account updates 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 account updates that 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 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 can update the root of the Merkle tree that is stored on chain.
On the next page, learn how to write a zkApp!