Learning How to Learn o1js

A more effective approach to building on the protocol by starting with provable code that leverages Mina's unique strengths as a verification layer.

image

Origins

Mina Protocol has a very long history, from its inception to its initial launch in 2021 to the Berkeley hard fork on Mainnet in 2024, which enabled Mina to verify arbitrary zk circuits. ZK has become very popular in the web3 world, and there are so many cool projects exploring its use cases, but back in 2018, the founders of what would eventually be called Mina had an elegant and audacious idea: What if we used ZK to operate a blockchain with a fixed-size state proof?

Ultimately, we succeeded and launched Mina in 2021. At that time, there were accounts and tokens, and you could prove the current state of all the accounts in the network with a fixed-size state proof. We are very proud of that work, but while web3 was going through DeFi Summer, we were launching a blockchain with only basic features. So, the work continued, and we began layering features onto the core radical idea of the succinct blockchain.

ZkApps

The same proof system that verifies the Mina blockchain state can be used to wrap other kinds of proofs and recursively verify them. This allows us to turn accounts on Mina into proof verifiers of arbitrary programs that we call ZkApps. I would recommend to anyone planning to learn Mina to review the MIP that proposed adding ZkApps to the protocol: MIP2. We call the DSL for generating these ZkApps o1js.

ZkApps have been the default entry point for learning o1js since day 1. The whole point of using o1js is to interact with Mina, right? So we began marketing the “hello world” of o1js as Add.ts.

image

This deceptively simple example has set our developer community up for failure, and I’m here to explain why, how we can fix it, and how this experience has taught me how to learn o1js.

Knowing Your Strengths

The fixed-size state proof of Mina is super cool and brings a ton of great properties to Mina, especially a reduced cost to participate in consensus and a reduced time to sync a node from scratch. The nature of recursive proofs also allows for unlimited execution of code offchain to be verified by Mina in O(1) time. This is an insanely powerful property of ZkApps. But Add.ts doesn’t make use of this at all.

On the other hand, generating proofs for each transaction creates some weaknesses. Mina is a very slow blockchain, and for a proof to be valid, the inputs to the proof must match the inputs to the verifier. That means two or more users can’t edit the same state in the same block. In other words, Mina can’t handle concurrent usage well. What this means for Add.ts is that two users can’t successfully add numbers at the same time, and it takes three minutes for either one of them to get their transaction included.

The interesting properties of Mina aren’t showcased well in this example. Mina can be used to compress lots of off-chain compute into a single on-chain transaction or prove something with a private input that’s not shared with the chain. Add.ts makes use of neither of these properties and could easily be implemented on a faster blockchain. The intention of this example was to simplify the world of ZK proofs and make it easier to onboard to Mina. We hear over and over again how intuitive our DSL is for writing proofs, so in some ways, this was successful. However, it also hides so much complexity about what is happening. It’s like there is a Mina development iceberg, and we’re only talking about the top.

image

Starting with Provable Code

I think that the trap of Add.ts is letting people believe that Mina is like Ethereum but with ZK, as if the ZK module is somehow layered on top of an Ethereum-like blockchain. Developers coming from web3 will have their own experiences optimizing for gas usage, protecting against unauthorized code execution, manipulating state with some kind of VM, etc… None of this applies to Mina. On Mina, a user or an application runs code on their own machine, generates a state transition + a proof, and sends that to the network to execute the state change. Mina is not an execution environment. Mina does not execute any o1js “Smart Contracts”. So, what kind of code do users or applications run on their owncomputers? Provable code.

By provable code, I mean code that can be compiled into a ZK circuit. o1js enables developers to write zk circuits that are composable with one another and exposes a TypeScript SDK to compile, prove, and verify these circuits. The zk circuits that are developed with o1js can also be verified by Mina. Mina’s secret sauce is that i can natively verify recursive proofs representing unlimited compute.

Since the SmartContract class has built-in complexity related to working with the Mina blockchain, I recommend starting with `ZkProgram` instead. `ZkProgram` is closer to a pure ZK circuit interface with clear inputs, outputs, and behavior, which makes it a great tool for writing provable code. Refactoring Add.ts into a ZkProgram gives us the following:

image

This code can easily be executed with a script like this (compared to the cumbersome interact.ts):

image

This refactor leaves the simplicity of Add.ts while removing the magic implicit behavior of the SmartContract version. A developer can quickly get their hands on this example, make changes, rerun it, and really make progress on their learning journey. Starting with provable code is the best and fastest way to learn how to build a ZkApp. Starting in version 0.22.9 of our zkapp-cli, we began shipping this new pattern for the Add example!

What is Interesting to Prove?

Let’s step back from Mina for a moment and just consider what is interesting to prove. One of the opportunities developers have with Mina is the ability to execute code however they want, rather than relying on the blockchain to execute their code for them. This lets us explore the world of ZK proofs off chain and bring distributed consensus back in when we want it.

Some ideas come to mind. One interesting thing to prove is that you’re authorized to access a resource on a website. Traditionally, this is done with a username and password or with a JSON web token attached to your session. With ZK, you can prove that you know a password without revealing it to the server. Or you could prove that you have a valid web token without revealing which user you are.

There are a lot of opportunities in gaming. A casino could prove that a deck was dealt in order and contains the correct cards. A chess tournament host could privately run the whole tournament, then use ZK proofs to prove that each game was played fairly and who the winner was. This approach could be applied to any game of skill where publicly revealing your past playstyle can give information to your future opponents.

Other cryptographic systems can be modeled with ZK proofs to make assertions about their correct execution. From something simple like proving a signature from Ethereum or Bitcoin contains a specific piece of information to something more complex like proving an entire block is filled with valid transactions or proving that a TLS handshake was made and specific content was transferred, there is a lot of interesting work to do modeling existing cryptographic systems in ZK.

Any of these domains can be interesting to prove, and with o1js, you can start writing constraint systems that are capable of proving and verifying statements even between two parties who communicate without a blockchain. The company can verify the users’ proofs. The player can verify the casino’s proof. The block proposer can verify the block builder’s proof. Where Mina adds value is in being the interoperability layer between all of these systems. In the same way that any two people can meet and exchange money without a blockchain, two parties can also meet and exchange proofs without Mina. But if you want to create permissionless, censorship-resistant, and globally open applications with proofs, then you need Mina as the unstoppable verification layer.

Layering Mina Over Provable Code

Once you have developed an interesting provable system, you can layer Mina on top to join the proof of everything. The good news is that ZkPrograms are completely compatible with Smart Contracts!

Going back to the Add.ts example, we can improve the original smart contract by using our newly developed ZkProgram:

image

Compared to the original example, which only added a number once per transaction, now we can recursively add infinite numbers and only call an update on Mina when we want to update the network state. Remember that Mina is a verification layer, not an execution layer. It is an excellent tool for proving that some computation was executedcorrectly. The more computation you can prove at once, the better it is. To make Mina approachable to web3 devs, we have, in the past, tried to make our examples look like how you might write a smart contract on another chain, but this was a mistake. We need to showcase how Mina is different from other chains and what we do better!

Learning How to Learn

We’ve been very fortunate to have an amazing developer community try iteration after iteration of o1js and give us feedback on the experience. If you actually take a step back and think about how crazy it was to attempt to bring zero knowledge cryptography to the masses when Mina started in 2018, you gain some perspective on the magnitude and the time scale of the problem we’re working on. Although it’s clear that there are not many ZkApps live on Mina currently, we are constantly learning what works and doesn’t, and we’re committed to getting it right. Going forward, we will revamp the Mina API in o1js to be more explicit. We will refocus our examples on highlighting the advantages of Mina. Thanks to the Mina community, we’ve made so much progress on the SDK, and we owe it to them to incorporate all the lessons we’ve learned into the next generation of onboarding materials.

Wrapping Up

If you know, you know how cool Mina is. Unlimited offchain execution, O(1) cheap verification on chain, and composable proofs that are verified once then enshrined on chain are a killer combination. If you don’t know, well, we’ll have to do a better job showing you! It all starts with provable code and onboarding new developers to the world of ZK proofs. It continues by guiding developers and founders who understand the building blocks toward how to put the pieces together into a production app. Finally, we supercharge Mina with performance upgrades and complementary services like Project Untitled that enhance the fundamentals that are already present.

Chat with us on Discord if you want to get involved 🧑‍💻, or check out our brand new o1js documentation site for more information about writing provable code!