We are happy to announce a first technology preview of our integration in Tezos of the core of the Sapling protocol developed by the ZCash project. By extending the Michelson smart contract language, this work allows for the exchange of digital assets in a privacy preserving way.
In recent years, we’ve seen much progress towards enabling privacy-preserving payments on public ledgers, both in academic research and in the real world deployement with projects such as Zcash, Monero, or Aztec.
In our opinion the Zcash project and in particular the Sapling protocol developed by the Electric Coin Company represents the state of the art to enable privacy-preserving transactions that’s available, in production, today.
As a result we have been working to integrate the Sapling protocol into Tezos as an instruction into the Michelson smart contract language for the past year.
What is Sapling?
Sapling is a protocol enabling privacy preserving transactions of fungible tokens in a decentralised environment. It was designed and implemented by the Electric Coin Company as the last iteration over a series of previous protocols and academic works starting with the Zerocoin seminal paper. Thanks to significant performance improvements of Sapling, privacy preserving transactions are finally practical, with approximately ~0.5s needed to craft a transaction and ~10 ms to verify it on a regular laptop. Note that the verification time is particularly important in a blockchain environment.
Sapling provides a slightly different set of keys from the ones existing today in Tezos. Each user generates a spending key which allows to perform payments (the equivalent of a secret key in Tezos) and a viewing key which allows to see the payments received or emitted. The viewing key can for example be shared with an auditor for regulatory compliance purposes without having to give the spending key . In order to receive a payment a user can generate an address from their viewing key and communicate it to the payer, much like a tz address today. Sapling addresses are diversified, meaning that from the same viewing key it is possible to derive new addresses which are not correlated to the previous one. This avoids the inherent leak of privacy happening with one public key where your different payers collude to realise that they are paying the same person.
Once our keys are set up we can start sending and receiving privacy preserving transactions, which are usually referred to as shielded . In a shielded transaction the amount transferred, the sender and the recipient are hidden. Only the sender and the receiver, using their viewing keys are aware of the details of the transaction. The state of the ledger for shielded transactions is usually referred to as the shielded pool .
In order to bridge a transparent ledger, like Tezos today, with a shielded pool, we need to shield and unshield transparent tokens. While shielded transactions are privacy preserving as explained above, any operation between the transparent ledger and the shielded pool does reveal that a certain tz address has just un/shielded a certain amount of tez.
It should be noted that as for every Privacy Enhancing Technology, there is no perfect system. It is important to follow good practices and to have a good understanding of what information your system is leaking. We will expand on this later.
Sapling in Tezos
What makes our integration in Tezos special is the fact that Sapling is exposed in the smart contract language Michelson. This makes it possible to effectively have a shielded pool in each contract, where tokens can be created and destroyed programmatically. A use case is for privacy-preserving STOs where any logic can be applied for the creation and destruction of tokens and where users can exchange their tokens while maintaining their privacy.
We created a very high level Michelson instruction called
sapling_verify_update , and two Michelson types called
sapling_transaction . The instruction takes a state (i.e. a shielded pool) and a transaction, checks that the transaction is valid with regard to the current state, and returns an updated state. It also returns the balance of the transaction, which is the difference between the number of shielded tokens created and destroyed. If the latter is bigger than the former the balance is negative and vice versa. This allows to program the logic for the conversion from and to the shielded pool directly in the smart contract. Note that transferring within the shielded pool has a balance of zero and nothing is revealed of the amount transferred.
A simple contract involving shielded transactions is one that accepts the creation of a shielded token in exchange for n tez. In this case a user with transparent address
tz1-alice will generate a sapling address
sapling-alice and a transaction that transfers n tez to the contract and asks for a shielded token to be credited to
sapling-alice . After the transaction is processed, the contract is credited n tez, Alice’s account
tz1-alice is debited n tez (plus the usual fees) and the contract will create a shielded token in its shielded pool.
Once Alice has a shielded token in the pool, she can send any number of shielded transactions to another shielded address. In this case, the only visible thing from the exterior is that a tz address (not necessarily Alice’s) is performing shielded transactions.
If Alice decides to unshield her token, she can send a transaction that destroys it and the contract will simply send to
tz1-alice n tez from its balance and burn the shielded token from the pool.
As for any smart contract, this template contract can be extended to adjust its rules programmaticall, interact with other contracts or with an oracle, etc.
Indeed with this technology it is possible to implement a privacy preserving version of FA 1.2 and the possibilities are endless.
When interacting with any smart contract it’s necessary to pay fees using a regular tz address and that’s also the case when sending a shielded transaction.
It is important that once Alice shields her token, she doesn’t use her
tz1-alice to submit her shielded transactions to the contract. This can be mitigated by using a service that acts as a proxy by forwarding Alice’s transactions to the contract and paying its fees. Alice can include in the transaction a shielded amount for the service that covers the fees plus a small bonus to pay the service.
When blending in a group of people, one should always pay attention to the size and the variety of the group. The size is important because if Alice and Bob are the only users in the shielded pool, and it only contains 10 tokens, whenever we see a shielded transaction we can still infer that Bob and Alice transferred less than 10 tokens. The variety of a set is important because if a shielded pool is used exclusively by left-handed people for example, then the mere fact of interacting with it may reveal your handedness.
We recommend two good practices. First, do not originate a second contract if another one has the same functionalities, it will split the anonymity set.
Second, remember that shielding and unshielding are public operations. A typical anti-pattern is to shield from tz1-alice 15.3 tez, and then unshield 15.3 tez to tz1-bob. It’s fairly clear from timing and amounts that Alice transferred 15.3 tez to Bob.
There are a number of more sophisticated techniques to deanonymise users using timing of operations, network monitoring, side-channels on clients and analysis of number of inputs/outputs just to mention a few. We advise users to be familiar with the use of the TOR network and to use clients developed specifically to protect their privacy.
What is ready
We invite more advanced users to try out our working branch sapling-integration. All the operations can be tested in sandbox using the simple contract we provide and our integration in the tezos-client. More detailed instructions can be found in the documentation.
What is almost ready
The storage of a smart contract using Sapling effectively stores a whole “blockchain”, with all the history of transactions. Therefore it could potentially be large and unwieldy. For this reason we are working on an efficient implementation much like the one used for big maps.
Specific RPCs will be added to interact with the new sapling storage.
Once the storage is ready, it will be possible to run accurate gas benching and compute the cost of sapling operations.
Conclusion and acknowledgments
We hope that the freedom given by creating a Michelson instruction will encourage developers to make creative use cases and that this will only be the start of financial privacy on Tezos.
We wish to particularly thank two groups of people. First, the cryptography research community that has been working on privacy and zero-knowledge protocols since the 80’s. Next, we would like to thanks the Z-Cash project and the Electronic Coin Company for their great protocol and for taking the time to write a superb specification (which can be hard to come by in our quickly moving environment).