The Blockchain Privacy Trilemma: Part Two
Welcome back! Firstly, apologies for the delay in getting round to part two. It was in part to working feverishly with the team on getting the Obscuro (now known as Ten) testnet ready, for which I’m proud to say is now open for applications.
In part one, I introduced various approaches to privacy. The focus of this post is to clear up some of the misconceptions around Zero-Knowledge Proofs (ZKPs), particularly in the context of rollups and privacy and present various ways ZKPs can and cannot optimise for the privacy trilemma.
Here’s the running order:
- show where ZKPs can optimise for privacy and decentralization only.
- show how ZKPs can optimise for privacy and smart contracts only.
- show how ZKPs can only optimise for smart contracts and decentralization only.
With that out of the way, we’re quickly going to enter into some complex reasoning, and it’ll require us to have the same mental models.
We need to first define the idea of an ‘Autonomous Agent’ as presented by Tudor Malene in this post.
Most commonly referred to as a “smart contract”, it is a program that runs on a decentralized platform that can accumulate and control any on-ledger value and, most importantly, has the power to dispense this value based only on coded predictable logic.
Another important property that it inherits from the underlying network and its logic is that it must be decentralized and censorship-resistant.
The reason for this distinction is that some blockchains do feature smart contract-like functionality, but they’re not truly autonomous.
Clearing up misconceptions around ZKPs and Rollups
One thing that surprised me is that people automatically equate privacy with ZKPs. If a solution uses ZKPs, it must also be private, right? It’s not, and the reasoning is pretty complex. So let’s start with ZKPs and rollups.
ZKPs are rightfully gaining attention to solve Ethereum’s scaling problems by applying them to rollups. ZKP rollups leverage a critical property of ZKPs that it’s far less costly to verify a proof than it is to create them.
Rather than have every node on the network process transactions or ‘compute proofs’, all we need to do is defer this proof generation to a single node. The node generates a proof for a batch of transactions. Then the rest of the network verifies the proof to determine the integrity of the transactions and accepts or rejects accordingly.
ZKPs are succinct and provide scaling capabilities beyond that of Ethereum.
Solutions such as Stark and zkSync do an incredible job solving these sorts of problems. However, they are not a solution to privacy. They are a solution to scaling.
The key to understanding this is to observe that whoever generates the proof sees absolutely everything!
1 — Privacy and Decentralization with ZKPs using UTXO networks
Not all blockchain networks require Autonomous Agents. Many blockchains exist that aim to optimise specifically for token transfers, e.g. Bitcoin and its UTXO model.
These networks are great at supporting the innovations of ZKPs. They make it impossible for any observer to detect the transferred amounts and participants involved.
Z-Cash is an example of one of these blockchains. It’s UTXO based with support for ZKPs to allow for the transfer of tokens privately. You can’t, however, use it to build something like Uniswap or Aave as it simply doesn’t support the notion of Autonomous Agents.
It works like this. A sender takes an input (some amount of Z-Cash belonging to them), creates an output (same amount of Z-Cash but now belonging to someone else) and then locally generates a ‘proof’ of this specific transaction. The network has specific mathematical logic covering the minimal rules required to verify the ‘proof’. For example, does the input amount equal the output amount or is the current owner a signee?
The initiator of the transaction has complete knowledge of the transaction. They are then trying to convey to the rest of the network that the transaction was valid.
ZKPs all revolve around a prover and a verifier. So let’s run through a model where every participant in an account-based network can act as the prover. It would require you as a transaction initiator to perform computations on contract code locally, generate a ZKP to prove that all the inputs to the contract were valid, and all should now accept the output (state change).
But the thing is, nobody can see what either that input or output is. All they can do is accept it must be right. But now, how would we ever maintain a consistent, truthful state of the ledger? How would miners understand the order in which to process transactions submitted to them? Suppose a group of other users and I were operating on a particular contract when I built the ZKP. In that case, my state changes could have been correct, but things may have changed since then, but nobody knows this. It’s impossible to maintain a global state and, by extension, impossible to prevent double-spending.This ability to produce a ZKP transaction that can be evaluated independently of any other only works for UTXO based systems where there is no need for global ordering of transactions.
Unconvinced? From part one, let’s remind ourselves of the account-based (Ethereum) vs UTXO (Bitcoin) models.
With an account-based model, every account has a balance, just like the experience you have at a bank. You log in to your banking portal or visit a cashier, and they look you up and provide you with your balance.
Any change in a balance for an account is like an accounting transaction. There’s a credit on one account and a debit on another.
With a UTXO model, each “state” has an owner. So if we think of Bitcoin, we can build a mental model where each Bitcoin or fraction of a Bitcoin is associated with a state that contains both the amount and the current owner.
Any change in Bitcoin is just a change in the ownership of a particular state. Just like when you hand physical cash to someone.
The beauty of UTXO transactions is that everyone else aside from the participants does not need to know what’s happening. The only thing the network needs to agree upon in a UTXO model is:
- has there been a double-spend
- have the protocol rules been followed, i.e. transition verification
Apart from that, you’re free to reassign ownership of a UTXO state.
In a privacy-preserving system, that’s not a big ask. All we need to do is register a change in ownership of the particular state. And what about the values? We don’t need to reveal the values to anyone as that’s not one of the things the network needs to agree on.
So let’s say Alice wants to send Bob 60 XYZ. If Alice has one 50 XYZ state and one 20 XYZ state, she would destroy the two existing XYZ states, totalling 70 XYZ and create two new states. One with a value of 60 XYZ and one with 10 XYZ.
It looks like this:
The critical bit the network needs to agree on, and prevent, is if Alice tried to spend either her old 50 or 20 XYZ states. This is doable without breaking privacy. We don’t need to go into the detail, but generally, ZKP networks create two sets of Merkle trees, one to track all states and another to track spent states.
But… suppose the network doesn’t see the values. How does it know that Alice and Bob aren’t in cahoots and, rather than the sum of the output values being equal to the sum of input values, Alice has created an output of 200 XYZ for herself?
And it’s here that the genius of ZKPs and UTXO is shown off. Alice generates a ZKP locally that proves she correctly computed the input and output state values. The entire network can verify this proof and convince themselves of this fact and record the new output states as the latest state of the world without ever seeing any of the values involved.
And here really is the crux of the argument — in a UTXO model, the system’s state is maintained as a directed acyclic graph. The sequencing or evolution of the current state is strictly dependent on what the previous state was, and these can all move independently.
In other words, there is no need for the notion of a global sequencer. UTXO is perfect for achieving privacy through ZKPs. You can keep values hidden, and the network can evolve in a somewhat disjointed way yet still reach a consensus.
As mentioned at the beginning, UTXO is great for the use-cases it was designed for, but it’s worth pointing out its limitations when it comes to some of the more complex privacy use-cases.
Let’s take, as an example, Constitution DAO. I made the case in a previous blog post that Constitution DAO would have faired better had its funding total been kept secret at auction. Let’s run through how Constitution DAO might work in a ZKP plus UTXO system.
Leveraging the power of ZKPs and UTXO, we can successfully fund an account owned by ConstitutionDAO and keep the values hidden from all (except the owner of the ConstitutionDAO account). But immediately, we see the first pitfall. There needs to be an account owner. We can’t just have the balance associated with an autonomous contract account. UTXO doesn’t allow for this. Check out this blog post if you’d like to dig more into why this is.
The other pitfalls quickly follow as soon as you begin to question what happens next.
What happens if ConstitutionDAO fails in its bid to buy a copy of the US constitution? Where is the logic to return funds? How does the auctioneer prompt a bid? We’re quickly restricted in what you can do once you remove contract accounts.
2 — Privacy and Smart Contracts with ZKPs
Where decentralization, scalability, censorship resistance and all the other great promise of blockchain is not required, then ZKPs become an interesting option to provide privacy with the power of smart contracts.
Let’s imagine a new DEX is launched. The first user will operate on the DEX, depositing a pair of coins to provide liquidity. They can maintain privacy over this operation by creating a ZKP and passing it to a sequencer which then operates on the DEX.
The sequencer passes back a result from the DEX to the first user and is now ready for the next operation. User two needs to request the new state of the ledger (which is a function of the ZKP from user one) and then produce a new ZKP, and so on and so forth.
Intuitively, you’ll see that what the sequencer is effectively doing is enforcing a two-phase commit and synthetically replicating the functionality that UTXO gives you for free.
The reason this can never scale vs a normal UTXO system is that the sequencer is now enforcing the input to output functionality you see in UTXO but in a non-parallel way. Rather than having all users create their own outputs from their own inputs locally, they now have to go through a central sequencer and operate only in series.
It goes without saying that if the sequencer goes down, the whole network goes on hold, so not an ideal system.
3 — Why ZKPs and Autonomous Agents can’t solve for privacy
I’m going to keep it relatively high-level, but for a sound technical explanation of why ZKPs combined with Autonomous Agents cannot work, see this other brilliant post by Tudor Malene.
In a UTXO system, there are only ‘user accounts’. Each user has control over the sequence of events that impact their own account.
Let’s contrast that with an account-based system, like Ethereum. All operations impact an account, and this can be either a user account or a ‘contract account’, and the network needs to reach a consensus on each account’s balances.
Now, given anyone can send commands to a contract account without an implicit ordering as we have with user accounts in UTXO, it’s impossible for an account-based decentralized network to maintain the order of events without an understanding of or view of the values (and commands).
The only way to solve this is by adding a global sequencer, i.e. an entity that is allowed to see everything and decide the order — and at that point, privacy is lost.
Another way to think about this is as follows.
- Ethereum is a global computer; every node that is part of the network runs the same smart contract code and needs to collectively agree on the ordering of events for contract accounts.
- In a UTXO system, only user accounts exist, and their ordering is inherent, i.e. every transaction must consume a valid input state. This allows for only the user to create a proof and convince the network of its validity.
- To achieve the same with Ethereum, given every node collectively owns the contract accounts, it would require every node to create a proof.
Hopefully, the above immediately draws out the contradiction — to achieve the same privacy ZKPs provide UTXO systems, you would require every node to be part of the group that sees everything — no privacy.
In an account-based model, everyone essentially plays the part of both the prover and verifier. You submit some transaction requests to alter the state of a particular Ethereum contract. That state change is run on the EVM by all nodes.
This is why, when you try and introduce privacy using ZKPs in an account-based network, you need a central aggregator/sequencer to control the order of things and maintain that global state.
ZKP privacy in account-based systems with autonomous agents cannot exist without sacrificing decentralization.
So this leads us down a path where the only way to have privacy would be to have a single or a few nodes that everyone can trust to create these proofs. That way, anyone else on the network can be confident that a particular computation has occurred correctly without seeing the inputs. You’d have privacy, except, of course, for the few nodes that can see everything.
How they could work
Some might point to Optimistic Rollups and argue that a centralized sequencer/aggregator is not centralized because we don’t need to trust them entirely, as anyone can challenge a transaction if it's invalid.
So let’s assume having one node that we can implicitly trust is ‘decentralized’. Can it ever be private? I think all paths lead to a particular outcome. Suppose we’re going to place all of our trust in this one operator to handle the world’s transactions. In that case, we need to make sure that the node, or more specifically, this node’s operator, cannot see all of these transactions as that’s way too much power for a single operator (or organisation to control).
So let’s turn our attention to how we might keep this sort of generation of proofs secret from the operator of this one single node.
One obvious way would be for this single node to run a Trusted Execution Environment (TEE). That would allow the node to calculate the proofs out of view of the node operator. With this, you’d have privacy.
Conclusion
From a technical standpoint, privacy is an enormous topic. There exist many approaches, each with its positives and drawbacks.
While an important technology and an incredible achievement, ZKPs are often poorly represented as the de-facto solution to all privacy problems. In practice, ZKPs are useful for privacy when a party with access to data wants to prove a claim to others without revealing the data to them. But in cases where we want to outsource computations, often involving multiple parties, there isn’t a single party we can trust with seeing all of the data. This is exacerbated in the smart contract setting, where the parties executing the computation are untrusted and pseudonymous.
These problems go away when you employ UTXO, as the protocol’s ability to control the order of events is inherent. There is no need for a single global state to be managed by all. This is why the ZKP solutions that claim privacy can’t provide account-based functionality. They solve simple things like token transfers by decomposing Ethereum contracts into UTXO processes.
None of the existing ZKP solutions claims to be Turing complete and private. They call out that they’re still working on it.
The project I work on, Obscuro, will ultimately be agnostic to the underlying technology providing privacy. Still, given the state of the technologies today, TEEs make the most sense as our first implementation. They’re heavily researched, are in the mainstream, are well understood, and work well. When combined with Obscuro’s POBI protocol, Obscuro provides privacy, decentralization and smart contracts.
Find out more
To learn more about Ten, dive into the whitepaper, chat with the community on Discord, and follow us on Twitter.