Exploring the Mina Protocol: Practical Use Cases for zk Applications
Zkapps (zero knowledge applications) are mina protocol smart contracts which are powered by zero knowledge proofs, specifically zk-Snarks [Zero-Knowledge Succinct Non-Interactive Argument of Knowledge].zkapps replaced snapps [Smart Non-Interactive Argument of Knowledge Applications]. ZkApp smart contracts are written using o1js (a TypeScript library). zkApps runs client side in a user’s web browser, and publish only a small validity proof which is then verified by the Mina nodes. Zkapp consists of smart contract and UI which I will further describe in the next section.
Application
I created zkapp regarding age verification where the user age gets validated without intervention to the personal data.
I proceeded by installing zkapp-cli npm package which actually created templates for proceeding with prover function and verifier function as part of the zk proof build process
Implementation
Below is the implementation of adding verification custom logic. It defines the circuit logic for zk-SNARKs, which is used during proof generation. The actual prover function is managed by the o1js library and invoked when zkApp methods are executed off-chain with private inputs.
import { Field, SmartContract, state, State, method } from 'o1js'; /** * Private Age Verification Contract * The contract will verify if the user's age is greater than or equal to the threshold age. * The contract uses zero-knowledge proofs to keep the user's age private. */ export class AgeVerification extends SmartContract { // State variable to store the verification result (valid or invalid) @state(Field) valid = State<Field>(); // Method to initialize the state init() { super.init(); this.valid.set(Field(0)); // Default is invalid } // Method to verify the age @method async verifyAge(age: Field, threshold: Field) { // Compute age - threshold const difference = age.sub(threshold); // Use circuit-compatible logic to check if the difference is non-negative const isValid = difference.equals(Field(0)).or(difference.greaterThanOrEqual(Field(0))) ? Field(1) : Field(0); // Set the validity of the verification result this.valid.set(isValid); } }
The below script is a test suite that interacts with the AgeVerification zkApp. It invokes the prover logic during txn.prove() and verifies the zkApp's behavior by checking its updated state.
The actual prover function lies in the underlying zkApp method (verifyAge), and txn.prove() is the mechanism to generate the proof during testing.
To test the inputs I have edited the test script as follows.
import { AccountUpdate, Field, Mina, PrivateKey, PublicKey } from 'o1js'; import { AgeVerification } from './AgeVerification'; // Import the correct contract let proofsEnabled = false; describe('AgeVerification', () => { let deployerAccount: Mina.TestPublicKey, deployerKey: PrivateKey, senderAccount: Mina.TestPublicKey, senderKey: PrivateKey, zkAppAddress: PublicKey, zkAppPrivateKey: PrivateKey, zkApp: AgeVerification; // Update to use AgeVerification instead of Add beforeAll(async () => { if (proofsEnabled) await AgeVerification.compile(); // Update compile for AgeVerification }); beforeEach(async () => { const Local = await Mina.LocalBlockchain({ proofsEnabled }); Mina.setActiveInstance(Local); [deployerAccount, senderAccount] = Local.testAccounts; let feePayer = Local.testAccounts[0].key; deployerKey = deployerAccount.key; senderKey = senderAccount.key; zkAppPrivateKey = PrivateKey.random(); zkAppAddress = zkAppPrivateKey.toPublicKey(); zkApp = new AgeVerification(zkAppAddress); // Instantiate AgeVerification contract }); async function localDeploy() { const txn = await Mina.transaction(deployerAccount, async () => { AccountUpdate.fundNewAccount(deployerAccount); await zkApp.deploy(); }); await txn.prove(); // this tx needs .sign(), because `deploy()` adds an account update that requires signature authorization await txn.sign([deployerKey, zkAppPrivateKey]).send(); } it('generates and deploys the `AgeVerification` smart contract', async () => { await localDeploy(); const valid = zkApp.valid.get(); // Access the 'valid' state variable expect(valid).toEqual(Field(0)); // Initially, the contract should set 'valid' to Field(0) }); it('correctly verifies the age in the `AgeVerification` smart contract', async () => { await localDeploy(); const age = Field(25); // Example age value const threshold = Field(18); // Example threshold value // Call the verifyAge method const txn = await Mina.transaction(senderAccount, async () => { await zkApp.verifyAge(age, threshold); // Use the verifyAge method }); await txn.prove(); await txn.sign([senderKey]).send(); const valid = zkApp.valid.get(); // Check the validity state after verification expect(valid).toEqual(Field(1)); // Expected to be valid if age >= threshold }); });
Below is the testing result
I have added the prover mechanism in interact.ts file which basically generates a zk-SNARK proof and submits the proof when it goes for transaction in mina blockchain. While the interact.ts script generates the proof, the verification is performed by the Mina blockchain when the transaction is processed. This is a key aspect of zk-SNARK systems that the prover generates a proof that the verifier (Mina network) checks.
import fs from 'fs/promises'; import { Mina, NetworkId, PrivateKey, Field } from 'o1js'; import { AgeVerification } from './AgeVerification'; // check command line arg let deployAlias = process.argv[2]; if (!deployAlias) throw Error(`Missing <deployAlias> argument. Usage: node build/src/interact.js <deployAlias> `); Error.stackTraceLimit = 1000; const DEFAULT_NETWORK_ID = 'testnet'; // parse config and private key from file type Config = { deployAliases: Record< string, { networkId?: string; url: string; keyPath: string; fee: string; feepayerKeyPath: string; feepayerAlias: string; } >; }; let configJson: Config = JSON.parse(await fs.readFile('config.json', 'utf8')); let config = configJson.deployAliases[deployAlias]; let feepayerKeysBase58: { privateKey: string; publicKey: string } = JSON.parse( await fs.readFile(config.feepayerKeyPath, 'utf8') ); let zkAppKeysBase58: { privateKey: string; publicKey: string } = JSON.parse( await fs.readFile(config.keyPath, 'utf8') ); let feepayerKey = PrivateKey.fromBase58(feepayerKeysBase58.privateKey); let zkAppKey = PrivateKey.fromBase58(zkAppKeysBase58.privateKey); // set up Mina instance and contract we interact with const Network = Mina.Network({ // We need to default to the testnet networkId if none is specified for this deploy alias in config.json // This is to ensure the backward compatibility. networkId: (config.networkId ?? DEFAULT_NETWORK_ID) as NetworkId, mina: config.url, }); const fee = Number(config.fee) * 1e9; // in nanomina (1 billion = 1.0 mina) Mina.setActiveInstance(Network); let feepayerAddress = feepayerKey.toPublicKey(); let zkAppAddress = zkAppKey.toPublicKey(); let zkApp = new AgeVerification(zkAppAddress); let age = Field(25); // Example age let threshold = Field(18); // Example threshold age // compile the contract to create prover keys console.log('compile the contract...'); await AgeVerification.compile(); try { // call verifyAge() and send transaction console.log('build transaction and create proof...'); let tx = await Mina.transaction( { sender: feepayerAddress, fee }, async () => { await zkApp.verifyAge(age, threshold); // Replacing update() with verifyAge } ); await tx.prove(); console.log('send transaction...'); const sentTx = await tx.sign([feepayerKey]).send(); if (sentTx.status === 'pending') { console.log( '\nSuccess! Age verification transaction sent.\n' + '\nYour smart contract state will be updated' + `\nas soon as the transaction is included in a block:` + `\n${getTxnUrl(config.url, sentTx.hash)}` ); } } catch (err) { console.log(err); } function getTxnUrl(graphQlUrl: string, txnHash: string | undefined) { const hostName = new URL(graphQlUrl).hostname; const txnBroadcastServiceName = hostName .split('.') .filter((item) => item === 'minascan')?.[0]; const networkName = graphQlUrl .split('/') .filter((item) => item === 'mainnet' || item === 'devnet')?.[0]; if (txnBroadcastServiceName && networkName) { return `https://minascan.io/${networkName}/tx/${txnHash}?type=zk-tx`; } return `Transaction hash: ${txnHash}`; }
I have used inputs for age and threshold as 25 and 18.
Since testing has been done successfully by running npm run test. I proceeded with deploying on devnet by using zk config
Where I provided following inputs:
Deploy alias: test
Network kind: testnet
URL: https://api.minascan.io/node/devnet/v1/graphql
Feepayer: New feepayer keys
Transaction: 0.1
The URL can be retrieved from here:
Then upon deployment I got the following response.
The contract is deployed at the following devnet
After deployment I proceeded with UI where I chose simple html, css and js by giving my RPC URL and deployed contract address and this is the final UI.
This concludes the creation of zkapp after integrating smart contract with UI. After building the user interface (UI) for the AgeVerification zkApp, the integration of the frontend with the smart contract allows users to interact seamlessly with the zero-knowledge proof system. The UI facilitates the submission of user age and threshold data to the contract, while maintaining privacy through zk-SNARKs. This enables users to verify their age without revealing the actual value, preserving confidentiality. The backend, utilizing the prover function, generates the proof, and the Mina blockchain verifies it efficiently. This end-to-end solution ensures a secure, user-friendly experience while taking full advantage of the privacy and scalability features offered by Mina's zk-SNARK-based architecture.
The above is the detailed content of Exploring the Mina Protocol: Practical Use Cases for zk Applications. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

Both Python and JavaScript's choices in development environments are important. 1) Python's development environment includes PyCharm, JupyterNotebook and Anaconda, which are suitable for data science and rapid prototyping. 2) The development environment of JavaScript includes Node.js, VSCode and Webpack, which are suitable for front-end and back-end development. Choosing the right tools according to project needs can improve development efficiency and project success rate.

C and C play a vital role in the JavaScript engine, mainly used to implement interpreters and JIT compilers. 1) C is used to parse JavaScript source code and generate an abstract syntax tree. 2) C is responsible for generating and executing bytecode. 3) C implements the JIT compiler, optimizes and compiles hot-spot code at runtime, and significantly improves the execution efficiency of JavaScript.

Python is more suitable for data science and automation, while JavaScript is more suitable for front-end and full-stack development. 1. Python performs well in data science and machine learning, using libraries such as NumPy and Pandas for data processing and modeling. 2. Python is concise and efficient in automation and scripting. 3. JavaScript is indispensable in front-end development and is used to build dynamic web pages and single-page applications. 4. JavaScript plays a role in back-end development through Node.js and supports full-stack development.
