Privacy Abstraction with Aztec

Aztec’s architecture is a departure from the current trend in blockchains of horizontal scaling via more general-purpose EVM-compatible execution environments. At Aztec Labs we joke we’re the first protocol not to build a zkEVM.

Instead, we are focused on one thing: becoming the ultimate destination for developers who understand and need smart contract privacy.

We are building a network and set of tools that gives developers everything they need to build privacy-first apps with:

  • Anonymity by default
  • Private state read/write functionality
  • Private smart contract function execution

In this piece you’ll learn why privacy on account-based systems like the EVM doesn’t really work, why Aztec therefore isn’t EVM-compatible, and how Aztec makes dealing with the unique architecture of private state environments as intuitive as possible for smart contracts developers used to EVM-like environments.

Why do this at all?

Since day 1, Aztec Labs has pursued smart contract privacy: private compute that doesn’t rely on trusted third parties or trusted hardware security modules.

And in a world with fully on-chain smart contract privacy, private state has to be a first-class citizen.

That means no EVM, no Solidity, and no account-based blockchain architecture, all of which are privacy-leaking.

Privacy isn’t EVM-compatible

Now you might find yourself asking, “Wait, why doesn’t the EVM support privacy?” And in fact there have been Solidity smart contracts that run on the EVM and provide primitive, non-programmable privacy functionality like mixing.

But we’re not talking about that.

We’re talking about smart contract privacy — an entire system that incorporates programmable privacy within the contract itself — at the level of state variables and functions.

In Ethereum’s model, state variables are stored in a public account-based tree, and to edit one of those variables you need to broadcast to the world exactly which leaves of the tree you’d like to edit, what they contain, and how you’d like to edit them.

This has some drawbacks.

  • The current and historic values of every state variable are public
  • The functions invoked to execute state changes are public
  • The state variables modified by those functions are public

Et cetera.

UTXO’s and nullifiers, name a more iconic duo

Instead of this nakedly public way of doing things, Aztec relies on an encrypted UTXO (Unspent Transaction Object) data architecture — the same technology Bitcoin uses to store network state.

The foundation of Aztec’s privacy design is an append-only data tree containing encrypted UTXO’s and another data tree containing their nullifiers. And we owe the original UTXO-nullifier design to the pioneers who created the ZCash protocol.

UTXO’s are also referred to as “notes,” and we’ll refer to them as such for the rest of the piece.

For a layman’s explanation of our UTXO architecture, see this post.

1*NT0CkEF9O2 JsoUOjr2PPw

In order to manipulate an owned note (which as a reminder are encrypted UTXO objects), users take the following steps:

  • A function is called
  • The function requests an edit to a private state
  • The function asks the user’s note database for all notes belonging to that private state
  • The user (in reality the user’s Aztec node) proves on their local machine that each of the retrieved notes exists as a leaf in the tree machine without revealing which leaf
  • The user does an action: read, change, or delete values inside the note
  • The user furnishes a nullifier, which prevents duplicate action and prevents the user from reading the same leaf ever again
  • The user inserts a new leaf, containing a new value, as a way of updating the private state’s value

A short history lesson

You can trace our obsession with notes back to our initial desire for smart contract privacy.

And one of the things “smart contract privacy” requires is hidden function inputs.

We started with zkSNARKs, which allow us to hide function inputs.

We then built Noir, an intuitive, open-source universal ZK language for writing functions whose inputs can be hidden. But Noir doesn’t have a built-in notion of state storage and state variables.

So now, we’re introducing a smart contract framework that creates state variable structs on top of Noir.

Let variables be variables!

So to have privacy, you need private state, and for private state you need private state variables.

But what are private state variables? Well they can’t be notes.

Notes stores data or information, and when combined with nullifiers they can preserve privacy, but notes are constant and immutable.

Variables are variable! They can be modified by the functions of a contract. So how can we create the concept of a private state variable using notes as a building block?

Well, as we saw above, notes can be destroyed and created. To create the abstraction of a private state variable, maybe we can cleverly destroy and create notes behind the scenes.

That’s exactly what Aztec does: declare a named private state variable, then write functions which read current state, edit that state, and write the updated state at the end.

Behind the scenes, these private state variable structs are figuring out:

  • which notes they need to gather as leaves in the private state tree
  • which notes they need to prove existence of in the tree
  • which notes they need to nullify
  • any new notes that need to be created and inserted into the tree

But to a developer, the variables just look like variables.

Private token contract example

To be less abstract, let’s think about the bread and butter of blockchain: a private token contract. The first thing a dev would wish to declare is a private_balance state variable.

Aztec allows a dev to declare a private_balance state variable, and then modify the balance in a transfer function.

Behind the scenes, the private_state struct that’s been exposed can figure out how to create and destroy notes in a way that represents adding-to or subtracting-from a user’s balance, all while not leaking that user’s balance (by emitting nullifiers from the function).

You can represent anything as a private state variable:

  • Values: an object with a value and owner field, like a banknote / $100 bill
  • NFTs: an object with a unique identifier, or that contains all the unique attributes of an NFT
  • Accounts: an object owned by one or many owners
  • and more! Votes, DeFi positions, identity objects, and anything else you can dream of

Private state variables store data or information, and can be programmed with two useful properties:

  • They can be mutable (updateable) or immutable (non-updateable); and
  • They can either comprise a single note (be a singleton) or comprise a group of notes describing a state variable (in this case a type of private state variable called a set)

It’s important to note (!) that notes are just used to store information, and don’t store functions or contracts. We will cover private and public execution in a future piece.

In case you can’t tell, managing UTXO’s would normally be a little bit complicated, and involves a few “gotchas” including how to:

  • Search the tree for one’s own notes efficiently
  • Combine notes
  • Make change from combined notes
  • Destroy and update notes with nullifiers

Unlike Ethereum accounts, which can simply be credited and debited, notes have to be created, combined, and nullified, which represents a distinctly different mental model. And where Ethereum values are just that — values — notes contain values.

Luckily, we at Aztec Labs have designed Aztec as a network with abstraction in mind. Our aim is to eliminate these difficulties and make writing Aztec smart contracts as similar to writing Ethereum smart contracts as possible.

Finally, while one of the benefits of our architecture is helping smart contract developers manage note complexity, one of the primary goals of this design is to abstract notes entirely from dApps.

Application developers rejoice! You’ll never have to think about UTXOs or notes at all, instead being able to call functions you would expect, like token.transfer(amount) or token.getBalance().

Passed around specific notes in an application would be extremely painful, and our smart contract framework helps abstract that completely from the dApp layer.

In the next post, we’ll cover Aztec’s smart contract framework and how it assists developers in managing private notes.

Start learning Noir today

Aztec Labs is a core contributor to Noir, the universal language of zero knowledge. We’re building an Aztec smart contract framework on top of Noir that extends its functionality beyond zk circuit writing language and toward private smart contracts.

Get started with Noirread the docs, and get ahead of learning the prerequisites for building on Aztec.

Jump into the conversation

The Aztec Labs team is committed to building our privacy technology publicly. Bringing a fully decentralized L2 with smart contract privacy to market means there is plenty of debate about network design.

Join the conversation at discourse.aztec.network and participate in the design of Aztec’s network and economics.

Join our team

Aztec Labs is on the lookout for talented engineers, cryptographers, and business people to accelerate our vision of encrypted Ethereum.

If joining our mission to bring scalable privacy to Ethereum excites you, check out our open roles.

And continue the conversation with us on Twitter.