This blog describes our new marketplace offering, the Zero Knowledge Token Transfer Service. The new service leverages Zero Knowledge Proofs to allow users to transfer ERC20 tokens confidentially and anonymously.
The underlying zero knowledge proof system is Σ-Bullets, proposed by Benedikt Bünz etc. in the paper Zether. The details about Σ-Bullets is outside the scope of this post, but they essentially allow Bulletproofs to work with Sigma protocols. Zether enables confidential token transfer between parties and allows for on chain verification of these transfers. We actually use the anonymous extension of Zether as proposed by Benjamin Diamond from JPMorgan's Quorum team, who adds anonymity to the confidential token transfers.
The service is currently available as a Kaleido Labs Service. This post covers a brief on why we chose Zether, how the service works, best practices for use and some gotchas to be aware of.
One of the greatest strengths of blockchain is data immutability, which is provided by having a decentralized group of parties maintaining a shared ledger. As a result, all data on the blockchain are shared with each party having a complete copy. In addition, all transaction execution are performed locally on each node, so transaction payload is also shared with every participant in the network.
In many use cases, especially with enterprise use cases, privacy is the topmost requirement. How to stay true to the blockchain’s architectural integrity while offering privacy becomes the topic of many leading research groups and technical communities alike.
Privacy is a broad concept and means different things to different people. At a high level, privacy encapsulates two fundamental concerns: confidentiality and anonymity. Confidentiality refers to the need to conceal the transaction details, in terms of what amount is being paid. Anonymity refers to the need to conceal the parties of the transaction, in terms of who is paying who.
Several approaches exist to address privacy requirements from different layers. They are applicable to different types of use cases.
Our current blockchain stack is mainly comprised of ethereum based networks like Geth, Quorum and Pantheon. Quorum and Pantheon provide support for EEA-compliant private transactions, which means verification of the private state is not possible to anyone who is not part of the transaction.
Zero Knowledge Proof systems allow for sharing of encrypted private state to everyone. Parties can submit transactions which include information (encrypted) to transition current state to new private state (encrypted) along with a proof which verifies that such state transition was a valid one.
Zether can be readily integrated into any account based smart contract platforms like Ethereum without any changes to the design of the platform. A basic Zether integration for confidential transfer of tokens works roughly like this,
Above description leaves out prevention of possible front-running attacks and how they are mitigated in the Zether design. Details can be found in the Zether paper. The paper also proposes how to make confidential transfer anonymous. That proposal is enhanced and extended by Ben Diamond from Quorum team in his anonymous Zether work. The transfers are modified to additionally encrypt 0 by public keys of the additional participants (let’s call them the decoys), along with a random number. Note that the anonymity feature comes at a cost, with the proof generation and verification time being O(N*logN), and proof size O(N), where N is the size of the anonymity set.
The Zether protocol applies transactions in epochs. Epochs allow for protection against front-running and replay types of attacks. A transfer or a burn proof can be successfully verified only in the same epoch that the proof is generated for. Since proofs are generated against current state of sender, a proof becomes invalid if sender’s state changes due to an incoming transfer. The result is there would be many failed transfer transactions due to failed proof verifications.
To prevent against this, epoch is introduced in Zether transactions processing. All transfers are put into pending state during an epoch and are only applied in a future epoch whenever the account is trying to spend the funds.
While epoch solves the state management problem between the proof generator and the proof verifier, it also requires careful arrangement of transfer transactions in the client application. Let’s use the diagram below to illustrate.
Epoch length in the above example is configured to the equivalent of three block periods. Transfer transaction 1 starts at time ts1 and ends at te1. Transfer transaction 2 starts at time ts2 and ends at te2. Same is true for transaction 3.
Notice that the proof for the first two transactions were generated during epoch 1, and both transactions were submitted before epoch 1 ended. Both transactions will be successfully verified as expected.
For transaction #3, however, the proof generation was started during epoch 1 and did not complete until epoch 2, but verification is performed during epoch 2. As a result, it was marked as invproof verifier inside the ZSC contract. The transaction is marked as failed by the EVM.
Epoch length is an important parameter which depends on block intervals, proof generation and verification times. Epoch length should definitely be greater than the sum of proof generation time, proof verification time and propagation time. This ensures that epoch used during the proof generation is the same one that is used during verification by ZSC. Epoch length should also be greater than the block period, should allow for multiple blocks to be published within an epoch duration. More on epochs later in best practices section.
Kaleido’s Zero Knowledge Tokens service can be added from the marketplace or the service catalog via the “Add -> Add Services” button in the environment dashboard.
This is a Kaleido member service, so each member of the consortium can provision their own instance in the Kaleido environment. In the initial release, the service is available to Quorum with both Raft and IBFT as consensus algorithm. Support for other protocols will come soon.
Once successfully provisioned, a user can interact with the service in the Kaleido service dashboard UI. Click on the service instance entry in the “Member Services” section to navigate to the service dashboard.
Notice a few key concepts as you step through the workflow:
Whenever the current balance of a shielded account needs to be acquired, such as when generating a transfer proof, or a withdraw proof, or querying for balance, a computation intensive step is required. This is a CPU-bound operation. To avoid the service to tie up CPUs and prevent other workloads to be processed in the shared infrastructure, the service currently limits total shielded balance to a relatively low number of 5000. This should still be enough to allow early tier kickers to try out the design and workflow, in order to determine if the functionalities meet their use case requirements. The Kaleido Labs team is working on improving the architecture so as to remove this temporary limitation soon.
Due to the epoch parameter being sensitive to the consensus protocol, bit of tuning is necessary to ensure they are set at the optimal value for the consensus. As a result the new Zero Knowledge Tokens service is offered on Quorum only at the moment. Of course our team is working on making it more widely available to other protocol providers.
The trickiest part of Zether is alignment with epoch. Our team at the moment can not completely guarantee that transfer transactions are submitted at the optimal point in time relative to the current epoch. As a result, you may experience transfer failures, especially on IBFT given its longer block period (10 seconds by default). We recommend trying it again which usually fixes the issue. If they continue to fail, please do not hesitate to contact Kaleido with a ticket.
A good performance indicator for the service would be shielded transfer transactions throughput. By design, currently only one transfer-out transaction can be made from a single account in an epoch. But an account can receive multiple transfer-in transactions in an epoch. Then the maximum possible achievable throughput would be number-of-accounts/epoch-length.
The epoch length is lower bounded by proof generation and verification time. The block gasLimit restricts the number of transactions inside the block. Either higher block gasLimit or having more blocks within an epoch will allow more transactions to go through. Kaleido already sets the targetGasLimit to maximum value, so block gasLimit will not be the performance bottleneck. For anonymity set of size 8, which we recommend, takes approximately 2200 ms to generate proof and 135 ms to verify. The gas consumption is around 27 million. [source: AnonZether]
We are currently working on benchmarking the proof generation and verification time on our platform with different resource settings and will update our findings. This would be part of a separate post on performance of Zero Knowledge Token Transfer Service.
There are several gotchas and suggested workarounds to help you understand and use the service better. This might not cover everything but feel free to reach out if you are stuck while using the service.
If your applications are hitting transaction failures during a transfer, most likely it’s due to proof generation vs. proof verification end up in different epochs. To mitigate this, we recommend two techniques:
The service currently allows users to generate only one shielded account (elgamal pair) per Ethereum account. This is a design decision in Kaleido to make the user experience easy to follow. The underlying ZSC implementation allows multiple elgamal accounts to be mapped to a single Ethereum account. So it’s conceivable that in the future this will be also enabled in the Kaleido service. If you have a use case that requires a single Ethereum account to be mapped to multiple shielded accounts, we would like to hear from you. The easiest way to contact us about such requirements is clicking the Contact Us button in the product.
Finally, you need to register the Ethereum account to shielded account mapping on ZSC contract before you can fund it and do transfer and withdraw from sender account. The withdraw operation will transfer the ERC20 funds to the Ethereum account to which the shielded account (elgamal public key) was registered with.
Anonymity is as good as the anonymity set and there is definitely a tradeoff between performance and size of anonymity set. The best case scenario will be to use all registered accounts in every transfer transaction but it would downgrade the performance and transfer might even fail if proof generation and verification times cross epoch boundary. The current implementation only allows anonymity sets of size of 2^k for k>=1. This is for efficient proof generation. For anonymous transfers, it is good practice to include keys that are funded. As it is easy to rule out accounts which were never funded, as decoys. It is also good practice to only withdraw from an account once it has been part of good amount of transfer transactions.
Besides private ERC20 token transfers, which is applicable in many enterprise use case scenarios, such as private payments, Zether can also be used in other patterns of applications such as blind auctions. The Kaleido Labs team will continue to collaborate with the open source community to make such patterns click-button easy to adopt.
Lastly, it is worth pointing out that the private token transfers pattern adopted by Kaleido’s Zero Knowledge Token Transfer service is agnostic to the specific underlying zero knowledge protocols. In the future, support for other protocols may be added to allow a variety of choices for clients with different skill sets.
If you have any questions about this service or Kaleido's solutions, feel free to contact us.