Introducing Aztec Tierra (Alpha V6)
The platform for unstoppable private apps is live. Major security upgrades, 2x speedup in private transactions, a growing ecosystem of private apps, and a bold new identity mark Aztec's next chapter.

In this article, we’ll talk about one of the core components unlocking privacy on Ethereum: state management. We’ll shed some light on programmable and composable privacy which allows dApp developers to choose what they want to make private and what to leave public. That allows for an ecosystem of privacy-preserving dApps that can communicate with each other as well as Ethereum.
From the early days of blockchain, great minds and stakeholders have been concerned about on-chain privacy. The reason is simple: no matter how excited we are about DeFi, on-chain identity, or any other area, it just doesn’t make sense to store all personal data on-chain. Doing so would make it accessible to anyone, anywhere, at any time.
However, to convert a system that is designed to be transparent into a private one is a tricky task. It’s even harder if the goal is to provide dApps with “privacy as a feature” (i.e. privacy should be optional and flexible) not something that changes a transparent system into a fully private one.
In this article, we’ll talk about one of the core components unlocking privacy on Ethereum: state management. We’ll shed some light on programmable and composable privacy which allows dApp developers to choose what they want to make private and what to leave public. That allows for an ecosystem of privacy-preserving dApps that can communicate with each other as well as Ethereum.
Building programmable and composable privacy on Ethereum is Aztec’s core mission. There are two critical pieces needed to make this happen:
In this piece, we will explore how different state modes enable this functionality, and explain how state management works on the Aztec Network.
For state management, Ethereum utilizes an account-based model. Whatever data needs to be stored, it takes the form of “key: value,” where “key” is derived from the account address, and “value” can be, for example, the account’s balance.
Here is a database showing some sample keys and associated values:

When a new transaction is executed, account balances are adjusted. For example, if Alice sends Bob $10, the new state will be the following:

This is the core property of the account-based model: account states are adjusted with each transaction.
But, what if we want a transaction—for example, a transfer—to be private? Can we simply encrypt all entries in the database to create privacy?

The answer is no, we can’t.
It leaks privacy.
If we execute a transaction on encrypted entries, people can still see which entries were modified: that constitutes a leak in privacy. If two transactions engage the same account one by one, it’s clear that this particular account state was modified.
By retrospectively analyzing account activity and the connections between them, one can retrieve tons of information. This means the account-based model doesn’t qualify for privacy needs.
UTXO stands for unspent transaction output. In the UTXO model, the account state is represented as a record of unspent assets.
Unlike in the account-based model, in the UTXO model, account states cannot be modified. Instead, the model operates in an append-only manner. Whenever someone needs to update an account state—for example, the balance—they have to destroy some existing notes and create some new notes.
Going back to our previous example, Alice transfers $10 to Bob.
The updated database is:

*In the example above, “crossed-out” indicates destroyed entries.
So using UTXO, if we want a transaction to remain private, we can encrypt all the entries without causing a privacy leak:

When one entry is destroyed and a new entry is created, observers can’t determine if these entries refer to the same account or to different accounts. No additional information can be gleaned by analyzing accounts’ activity.
And that’s exactly what we need.
Aztec utilizes the UTXO model for private state management and the account-based model for public state management. Public state is universal (i.e. one for the whole network and available for anyone) while private state is individual to every user.
A smart contract on Aztec consists of both private and public functions. When a smart contract is executed, the first thing that happens is all private functions are executed client-side and the user's private state is updated. After that, all public functions are executed and the transaction execution is reflected in the public state update.
As we discussed earlier, for the sake of privacy, private state operates in the append-only mode. At the same time, modifying an entry in the UTXO model means “destroying” the existing entry (or multiple entries) and creating new entries reflecting the transaction. (In our example, a note with a transfer to the receiver and Alice’s updated balance).
How can the note be destroyed in an append-only mode? Using nullifiers.
A nullifier is a commitment corresponding to a private entry that was destroyed. Only the note owner is aware of the correspondence between notes and nullifiers. For everyone else, it’s impossible to define which nullifier was created for which note.

Every note can be consumed only once. When a new transaction emits a nullifier the sequencer has to check that this nullifier hasn’t existed before (to prevent double-spend).
Let’s circle back to our example: Alice has $100 and she is sending Bob $10.


Let’s think of another example. Alice has two notes, $50 and $60, and she wants to transfer $100 to Bob. For this transaction, she has to destroy both notes, emit a note for Bob with a value of $100, and emit a note for herself updating her remaining balance of $10. That is to say that an arbitrary amount of notes can be consumed per transaction.
More generally, any state (i.e. not just balances) can be represented with notes. For example, if someone keeps a counter that they increase every time they send a transaction, they can store the value of the counter in a note. Every time they send a new transaction, they nullify the existing counter note and create a new one with the updated value.
Although notes and nullifiers are emitted client-side, it’s the sequencer who grabs the notes’ hashes and nullifiers (as commitments) and adds them to the databases (i.e. updates the state). That is to say, a client is always running its private execution environment in an “old” state.

However, what if someone picks an old state root that satisfies some logic that the current state root would not satisfy?
Circling back to our second example, imagine someone has a note where they keep an increasing counter. The counter owner is allowed to do something only if that counter is less than 10. So they can always pick a state root where the counter was less than 10 (even if it was 10 years ago) and just run their transaction over that state.
To mitigate this issue, the note must be nullified even if it was only read without spending it. This introduces the nullify-on-read concept that whenever someone reads a private note and performs some action on it (e.g. reading a note grants permission to make a call), they must nullify it and recreate it with the same value. Which means the content of each unique note can be read only once.
In this article, we’ve explored the core concepts behind Aztec’s state management mechanism, which allows builders to get programmable and composable privacy. Now, it’s your turn!
Ready to put your hands on on-chain privacy and kick off the next big thing for Ethereum? – this is your next step.
Stay updated on all things Noir and Aztec by following Noir and Aztec on X, and join the Aztec developer community on Discord.