Tachyon: Scaling Zcash with Oblivious Synchronization
2025-04-02 by Sean Bowe
Zcash’s shielded transactions offer the strongest privacy guarantees of any distributed financial network today. They provide a cryptographic property we call “ledger indistinguishability,” which delivers strong on-chain confidentiality — far beyond what’s achievable with decoys or cover traffic that only partially masks transaction details. In short, shielded transactions resemble random gibberish paired with a proof that it actually represents a valid payment.
To enable this, Zcash pioneered the use of zero-knowledge proofs — a technique that allows the network to verify transactions without revealing their private contents. These proofs are called “zero-knowledge” because they reveal nothing about the transaction’s internals. But the cryptographic techniques behind this — particularly the proofs we use called zk-SNARKs — are also powerful tools for building scalable decentralized systems. Their power lies not just in the zero-knowledge property itself (which is often unused in practice), but in their ability to succinctly prove the correctness of large computations.
Today, many projects use zero-knowledge (“ZK”) as a marketing term, with little to no regard for actual user privacy. We can have the best of both worlds — a private digital payment network that scales to billions of users — by fully leveraging both zero-knowledge and verifiable computation. We've invested heavily in making this happen, first through the discovery of Halo — which led to a revolution in efficient, scalable verifiable computation — and then through the Orchard payment protocol, which laid the groundwork for the next generation of upgrades.1
Now it’s time to cross the finish line. I am proposing several protocol changes in Zcash that allow us to increasingly scale the protocol while providing a smooth transition path for existing users and wallets. The crucial component that makes this possible is a new model for how wallets interact with the blockchain that I refer to as oblivious synchronization. This new approach improves the user experience for wallets and permits an architectural change to the protocol that maintains ledger indistinguishability without incurring heavy state contention, storage and bandwidth costs for validators.
Crucially, it is an actionable plan that does not require speculative research to see to fruition. In the short term it can be deployed using the cryptography we're already experts at deploying in Zcash, leaving some remaining challenges for more longer-term research in the future. In order to make this happen we must pursue an engineering effort much like the “Sapling” upgrade from earlier in Zcash's history. Back then, we set out to make zk-SNARKs practical enough to run on mobile devices — a capability that’s now taken for granted. The sophistication of the Sapling upgrade (and the coordination required to pull it off) remain nearly unmatched across the entire blockchain space.2
Here's what it will take to raise the bar again.
🔗Proof-carrying Data
Early in the history of Zcash our shielded transactions earned a reputation for being expensive due to the use of zk-SNARKs. As mentioned, the Sapling network upgrade incorporated a slate of cryptographic improvements from our team3 and from the academic world4 which made our proofs extremely efficient to generate. However, zk-SNARKs are also known for being slow to verify when compared to bog standard digital signature schemes. This has led to a misconception that zk-SNARKs are the cause of performance and scalability bottlenecks in Zcash.
In reality, we've never actually considered zk-SNARK verification a barrier to scaling Zcash. I once co-authored a paper5 where we devised a method to batch verify proofs as efficiently as checking a single proof, with the help of an untrusted third party's computational resources. Later results in proof aggregation—analogous to digital signature aggregation in other protocols—allowed multiple proofs to be combined and efficiently verified as a single unit, a notable example being SnarkPack6 which has been deployed in some blockchains.
The ultimate tool for scaling zk-SNARK verification and a wide variety of other computationally intensive tasks in protocols like Zcash is a more general technique called proof-carrying data (PCD) that was originally devised and even realized by the scientists behind Zcash. Crudely speaking, PCD allows data to live alongside proofs of its own correctness so that when it is combined with other (proof-carrying) data the mixture inherits and extends the original proofs of correctness. This can be used to “compress” a huge amount of verifiable computational effort, since the resulting data does not need to grow in size and there is no practical bound in the complexity of the inductive claims.7
PCD languished for years as a theoretical tool due to performance limitations. This changed when our team at the Electric Coin Company discovered Halo, which was a brand new approach to achieving PCD with significantly better performance while also avoiding trusted setups and strong cryptographic assumptions. As mentioned before, this led to a Cambrian explosion of new results8 that has made PCD table stakes for new scalable protocols. PCD can be leveraged to make Zcash's blocks small and fast to verify no matter how many shielded transactions they contain, and it can even be applied to the chain itself to build fully succinct blockchains.9 As we'll be discussing, they can be used in other ways to improve our network's transaction throughput.
🔗Communicating State Changes
zk-SNARKs and PCD are indispensable tools for maintaining privacy while enforcing correctness in contexts that do not involve high state contention—such as within a single transaction or across a long-term history of transactions. However, privacy-preserving protocols like Zcash involve communicating and coordinating global state changes because shielded transactions must be made indistinguishable from one another to reach our lofty privacy goals.
There are three major areas where this becomes a concern in our existing protocol:
- How do users learn about the payments they receive and the information they need to spend those funds?
- How do users later demonstrate that the funds they are spending actually exist?
- How are users prevented from spending funds that have already been spent?
Zcash's current protocol solves these problems in a way that is maximally convenient for the zk-SNARKs (due to legacy concerns about their performance) but otherwise very inconvenient or even impossible to scale to large numbers of users and payments. By being open to some common sense changes to the underlying cryptography and payment protocol we can take full advantage of the modern performance of zk-SNARKs and PCD.
🔗Shielded Notes and Commitments
Shielded transactions involve spending and creating “notes,” which represent an amount of funds and the key authorized to spend them — not unlike UTXOs in Bitcoin. We aim to leak as little information as possible about the notes being spent or created in a transaction, instead allowing the zk-SNARK to prove that various rules are being followed. In order to keep newly created notes private they are encapsulated in a cryptographic commitment that is exposed publicly in the transaction.10
The commitment hides the note, but the zk-SNARK can still reason about the note because the transaction creator can open the commitment using a random, secret key. This allows the zk-SNARK proof to enforce local rules for things like “balance integrity” (the sum of the funds in new shielded notes does not exceed the sum of the funds being spent) and “spend authorization” (that we know the secret key associated with the notes being spent). In order for the recipient to later spend the funds they must also learn this random key and other payment information, necessitating a secret distribution system.
Secret distribution systems are not ordinarily needed in blockchain protocols. The standard payment flow in most cryptocurrencies works like this:
- The user asks their wallet for a payment address.
- The user gives this payment address to one or more other people.
- Other people use this address to make a payment.
- The user scans the blockchain to find all the new payments to their address.
This is how Bitcoin and most other cryptocurrencies work, and it's possible because addresses and payments are not private. The user can ask a third party (like a light wallet server or block explorer) for all the payments made to an address and those services can index the blockchain and answer these queries in a way that quickly enables the user to spend those funds. In private cryptocurrencies like Zcash we cannot ask a third party to identify payments sent to our payment address. In order to see incoming payments we must allow the sender to encrypt the relevant information and send it to us.
Zcash lets senders place ciphertexts inside of shielded transactions that contain note information. Recipients identify incoming payments by trial decrypting every transaction until they identify payments sent to them. This simply does not scale.11 As a start, we'll be assuming that Zcash's future payment flows involve out-of-band payments where the sender and recipient use a separate channel for secret distribution. The on-chain ciphertexts can then be removed from the protocol entirely.12
Fortunately, it is common for a pre-existing channel to already exist between the sender and recipient: a user paying a merchant through a web interface, someone buying coffee within physical proximity to a payment terminal, or friends resolving dinner debts over Signal chats. In these cases the payment request model that is supported by most Zcash wallets (and commonly found in most cryptocurrencies) accomodates out-of-band payments. It is even possible for payments to be sent to recipients out-of-band without a payment request through the use of “liberated” or URI-encapsulated payments.13
There are some drawbacks that have to be addressed separately. By moving secret distribution out-of-band the user cannot rely on the blockchain as a storage mechanism for recovering their funds from a seed phrase or sharing transaction histories with view keys. Also, the ability to give a payment address away publicly (like posting on a billboard to solicit anonymous donations) does not inherently work.14 In order to support these use cases we will need additional infrastructure for our wallets to store and distribute payment information privately. This at least makes sense from an economic perspective, since the blockchain currently provides for these use cases for free at great systemic cost.
🔗Accumulators and Nullifiers
In order to spend a shielded note that has been previously created, validators continually append the new note commitments that appear in shielded transactions to a cryptographic accumulator. Currently, at block boundaries, the accumulator is checkpointed and a succinct (hash) representation of that checkpoint is stored by validators. We call this checkpoint an “anchor.” In order to spend a note later, shielded transactions demonstrate that the note they are spending exists at some (usually recent) anchor that validators accept as valid.
In order to maintain privacy, while shielded transactions must publicly identify the anchor (for validators to check) they do not need to identify the actual note commitment they are spending. This works because a set inclusion witness that demonstrates a commitment exists within an accumulator can be short and easy to verify, and so the zk-SNARK proof in a transaction can be used to demonstrate knowledge of such a witness without revealing it publicly.
If we do not identify the note being spent, how do we demonstrate that it has not been spent by another transaction? The zk-SNARK helps us verifiably compute a value called a nullifier that is deterministically derived in some way from the note we are spending. The nullifier itself does not reveal anything about the note, but because it is forcibly disclosed within the transaction it serves as an indelible mark on the chain state that prohibits double-spends. Validators currently remember all of the nullifiers seen before and reject payments as invalid if they reveal a previously-seen nullifier.
The scalability bottlenecks that remain in Zcash center around how wallets synchronize with these particular blockchain state changes. Currently, even with out-of-band payments, every time any user creates a shielded transaction in Zcash:
- the network must ensure that the revealed nullifier has never been seen before;
- the network must record the nullifier so that it cannot be repeated again; and,
- all other users must account for the newly created note commitments by updating their set inclusion witnesses for all of their unspent shielded notes, to reflect a more recent anchor.
🔗Oblivious Synchronization
It'll be helpful to recast what a Zcash wallet does through the lens of an abstract machine, focusing (without loss of generality) on the case that the wallet only receives and later spends a single shielded note.
The wallet starts in some initial state (at some point in the blockchain) and processes blocks one at a time. In each block, it attempts to find a new note commitment that it expects to find based on the out-of-band process mentioned previously. Once found, the wallet enters a synchronizing state. In all of the blocks that follow, the wallet checks to make sure the block does not contain the nullifier for the note to ensure it has not been spent already. As long as it hasn't the wallet remains in this synchronizing state.
Finally, when the user is ready to make a transaction, they use the wallet's state to create a zk-SNARK proof and spend the funds. (The wallet's state contains, for instance, the set inclusion witness needed to spend the note with a recent anchor.) This is more or less how our wallets currently work.
My vision for scaling Zcash is to fully embrace a new model for how Zcash wallets should synchronize with blockchain state changes. Rather than using the wallet's state to merely inform the process of creating a zk-SNARK proof when it comes time to spend, we will also represent our wallet's state as proof-carrying data. This means that as the wallet state updates to reflect new blocks it will continually maintain a proof of its own correctness. Then, when it's time to spend our funds we will extend our transaction with this proof-carrying data. This effectively attaches evidence that the transaction is valid up until a certain recent point in the history of the blockchain — the position of the anchor.
The result is that validators are now only responsible for ensuring that the transaction is correct in the presence of the additional transactions that appeared in the intervening time, which just involves checking that the most recent block(s) do not contain the revealed nullifier.15 As a result, almost everything in a block can be permanently pruned by validators and ultimately all users of the system as well. Despite transactions sharing a common state by being indistinguishable from each other, nearly all state contention problems vanish in this new approach.
It would seem for this model to work that the user's wallet will have to follow a much more expensive synchronization process to create and maintain PCD of the wallet state. This expense is not just due to the cost of creating PCD proofs but also the bandwidth needed to apply every block to the wallet state.
However, we can arrange things so that the user's wallet can outsource the process of synchronizing the wallet (and creating the PCD proofs) to a third party that I call an oblivious syncing service. This service isn't trusted with private information or secrets and learns nothing about the notes in the user's wallet, yet it can still make progress synchronizing its state even when the user's wallet software is offline.
We already know that this kind of approach is possible with expensive cryptography like fully-homomorphic encryption (FHE). But by adjusting the protocol slightly we can simply use PCD. The remote server only needs to learn the nullifier of the note to make synchronization progress without the assistance of the user's wallet, since the wallet can blind or encrypt the rest of the wallet state and only permit the oblivious syncing service to make state transitions involving the nullifier. One would expect this to reveal some information to the service about the note's possible location in the accumulator, but by adjusting how the nullifier is derived in the protocol16 we can eliminate this information leakage entirely, depriving the service of any information about the note being spent.
In practice the wallet will be handling multiple notes and thus multiple nullifiers, and so an oblivious syncing service might learn more information if it can correlate requests as originating from the same wallet. But this same kind of leakage occurs already anyway when the transactions themselves are published, and so we must tackle the problem at least partially with network privacy countermeasures like mixnets. Fortunately, as I'll explain in a future blog post, even if the oblivious syncing service can correlate nullifiers we can completely sever the link using nifty cryptographic techniques and protocol adjustments—it's just a matter of finding the most efficient point in the trade-off space.
🔗Project Tachyon
This new model of wallet synchronization and validator state pruning can be enabled with several compartmentalized changes to the existing protocol that can happen in independent tracks, providing an immediate capacity increase in the Zcash shielded payment protocol at each step. The main changes involved include:
- Wallets need to adopt out-of-band payments. ECC has already begun exploring the incoporation of URI-encapsulated payments into its Zashi mobile wallet. Different kinds of out-of-band payment flows will require changes to the way existing wallets use payment requests. Fortunately, almost all of this is reverse-compatible and can be deployed without any changes to the Zcash protocol. It also leads to immediate usability wins for shielded wallets even without capacity improvements.
- Blocks need to incorporate shielded transaction aggregation. This involves implementing and deploying a PCD-based proof aggregation protocol for Orchard payments, which we've already been considering for years17 and ensured the Orchard payment protocol could later accomodate. This can land in a network upgrade without any other changes to wallets or the underlying payment protocol and leads to an immediate capacity increase.
- Nullifiers should be derived differently to prevent oblivious syncing services from learning sensitive information about wallets. This can be achieved with a backwards-compatible network upgrade, though it will require a circuit change.
- Nullifiers (and potentially also note commitments) must be batch inserted into a new accumulator that supports efficient set (non-)membership testing in PCD. I've already sketched a very simple and efficient accumulation scheme for this. This will allow the development of oblivious syncing services without any immediate changes to the payment protocol that would risk user funds, and can be done in a network upgrade with high assurance.
- In-band secret distribution must be removed in Zcash. This can be achieved once wallets have migrated away from the legacy payment protocol(s). Efforts in this direction can happen independent of any protocol changes.
- The payment protocol should allow wallet PCD state to augment the zk-SNARK in transactions. This final major improvement allows validators to begin pruning all old blockchain state and reduces state contention considerably. This can be paired with a corresponding increase to block sizes and/or frequency.
I call this the Tachyon project for Zcash. I'm excited that all of these steps are possible, can be done using cryptography we are already experts in deploying, can be developed in parallel tracks, and involve few changes to the actual payment protocol. My goal is to faciliate these efforts on an ambitious timeline: many of the major scalability improvements should be able to hit mainnet within a year, while the more involved changes will depend on how quickly wallets can migrate from legacy payment protocols. As with all of our previous network upgrades I'm committed to shipping high quality code that protects our users' privacy.
Crucially, I don't plan to stand in the way of any other Zcash protocol improvements while I see Tachyon to fruition. I'm not asking the community for grants or financial assistance at this time, and I'm not asking any organizations to redirect resources to Tachyon that they think are better spent elsewhere. I also have no reason to believe that Tachyon will conflict with any of the active areas of development such as Crosslink and ZSAs; in fact, I have more reason to believe these protocol enhancements will be mutually beneficial for Tachyon.
There are many things I'll be sharing over the coming weeks. I'm most excited to publish benchmarks of a proof-carrying data toolkit that I've developed to be compatible with the Orchard payment protocol, with the goal being to set a floor on the performance of shielded transaction aggregation and oblivious syncing services. This should begin to reveal the magnitude of the scalability improvements we can expect and the complexity of the path forward.
Stay tuned, and please get in touch if you'd like to help!
Orchard is a new shielded payment protocol that supplants the Sapling protocol. It is based on a new set of elliptic curves designed specifically so that they can be efficiently used in modern PCD constructions based on Halo.
Henry de Valence from Penumbra has fondly refered to Sapling as the “apollo project of cryptography”.
We developed the Jubjub embedded elliptic curve and BLS12-381 pairing-friendly elliptic curve and used these to build efficient zk-SNARK circuits for commitment schemes and hash functions for Merkle trees.
Groth16 is one of the most efficient zk-SNARK constructions currently known.
Sonic was the first practical universal zk-SNARK construction, but in its most efficient setting it leveraged a non-trusted “helper” to assist verifiers in checking large numbers of proofs more efficiently than with traditional batch verification techniques.
There is a theoretical limit to the (recursive) soundness claims of known PCD constructions relative to a fixed security level, but there are no known attacks and this is largely ignored in practice.
Halo [BGH19] presented a new technique for achieving recursive SNARK composition that was formalized and generalized into the concept of an accumulation scheme in [BCMS20]. Among the numerous follow-up papers in this area, later results loosened the requirements of these schemes for efficiency ([BCLMS20], [KST21], Nova and folding schemes [KS22], [KS23] [BC23], [EG23]) or to target post-quantum cryptography ([BDFG20], [BMNW24], [BC24], [BC25], [NS25]).
Mina, the only succinct blockchain ever launched, uses a variant of Halo and the elliptic curves we designed for Halo and Zcash, though Mina itself does not target private payments.
Commitment schemes can be realized using strong hash functions, but the commitments we use in Zcash today have a richer structure that allows them to perform better and offer information theoretical privacy guarantees.
The possibility of delegating the identification of incoming payments to a third party has been explored through the use of detection keys, but even when the privacy trade-off is acceptable this does not actually address the expensive cost of broadcasting, relaying and trial decrypting ciphertexts for every shielded transaction.
This comes with the added advantage of removing all privacy-sensitive components of our on-chain protocol that are not yet using quantum-resistant cryptography.
These have a natural “viral” quality because funds can be sent to people who do not yet have Zcash wallets.
Payment requests behave like one-time capabilities to send a payment to a recipient. In order to accomodate the traditional "payment address" style of payments for arbitrary numbers of senders the user's wallet will need to negotiate with (an agent of) the recipient's wallet via an active channel, which might require the use of store-and-forward services and/or mixnets for privacy.
Together with the proof of the wallet's validity, this demonstrates that the nullifier did not appear in another transaction that followed the block that created the note commitment being spent. Notably, this loosens the condition that the nullifier has never been seen before in the history of the blockchain but still manages to prevent double-spending.
In particular, nullifiers need to be changed so that they are not determined by the note commitment but rather the other way around. This can be done by altering the derivation process in ways that would ordinarily allow for certain kinds of attacks in the existing protocol, but these attacks can be mitigated in other ways when payments are made out-of-band instead. My presentation at Zcon VI briefly sketches what needs to be altered.
See this github issue where the idea is explored in detail.