Confidential Transactions
Private payments may be designed for two properties - anonymity and confidentiality. Anonymity hides one or both of the sender and recipient of a transaction. Confidentiality hides the amount sent. Two cryptocurrency projects which attempt to provide both confidentiality and anonymity are ZCash and Monero. In general, anonymity is a harder problem than confidentiality. The 2019 Zether paper designed for the account-based model used by blockchains such as Ethereum and Solana provides confidentiality without anonymity. Two projects I am aware of outside of the EVM have implemented variants of Zether. They have manifested as Solana’s Confidential Transfers and Aptos’ Veiled Coins. The former is a production-ready deployment integrated with Solana’s L1, while the latter is implemented as an example smart contract in Move not ready for production. This post will explain these two systems, explaining their designs and features, while also comparing them to the original Zether design.
Zether - What’s It All About
The Zether paper is based on the simple insight that confidentiality can be provided in the account-based model using a partially-homomorphic encryption protocol. If we represent two encrypted ciphertexts
Say a user’s hidden encrypted balance is represented by
This is pretty simple, but there are two main problems. One is that we must know that the sender is not sending more money than they actually have. This can be fixed by using range proofs to verify that the sender’s updated balance
We need a second range proof as well, for reasons that are a bit more subtle. The encryption scheme we will choose will work over a cyclic group
The recipient here has their balance encrypted under a public encryption key, let’s call it
This can be fixed. Denote
To encrypt, the user computes the following ciphertext, consisting of two group elements:
Note that for this to work, the value
How to Prove It: Gimme that Sigma Rizz
One core ingredient here is missing. We need some way of proving that
Let’s break this down a bit. The sender has public key
The first four equations in the relation are fairly easy to understand. The first,
The fifth line is where things get a bit more interesting.
It can be seen that the above relation can be easily proven by an extended version of the Schnorr identity protocol. In particular, on the prover side we sample 4 random scalars
and sends each
before sending each
To verify the proof, the verifier checks that the following equations hold:
If all checks pass, the verification passes.
Completeness of the above is easy to verify. Knowledge soundness and zero-knowledge may be proven using arguments analogous to those used to prove security of the Schnorr identification protocol.
After the proof is verified on-chain, the sender’s and the recipient’s balances are updated as discussed before, with the transacted amount being homomorphically subtracted from the sender’s balance, and added to the recipient’s balance.
NOTE: The fact the sigma protocol uses
Come on and Twist
A protocol using relation above, however, is actually insecure as presented. In particular, range proofs such as Bulletproofs must be done over two fixed generators
The Zether paper gets around this problem by implementing what they describe as
There are two other potential solutions for this which have a lower implementation complexity. The first and inferior solution is implemented by the Aptos Veiled Coins module. This is to both encrypt
where
The second and superior solution is implemented by Solana’s Confidential Transfers. Instead of using standard ElGamal encryption, we can use twisted ElGamal encryption, introduced in the PGC: Decentralized Confidential Payment System with Auditability paper in 2019. In this scheme, key generation is slightly different. While the secret key as before is any random scalar
Encryption is also slightly different, being done as
To decrypt using twisted ElGamal, we compute
Because we do not need extra Pedersen commitments, we both save on storage space and eliminate the need for the additional two lines in our sigma protocol. The protocol does need to be modified slightly to account for the change in encryption scheme, but this is not too difficult to work out and is omitted here for brevity.
Withdrawals and Deposits: How Can I Get My Money Out?
To deposit funds into a hidden balance, no proofs are needed. The deposited amount is simply encrypted under the user’s encryption key, then homomorphically added to their hidden balance, although this unavoidably reveals the amount deposited.
To withdraw an amount into a normal unencrypted balance requires another proof similar to but shorter than the proof for a fully concealed transaction. The NP relation required to be proven for a withdrawal is as follows. Given public group elements
where
We also require a range proof over
to the NP relation, and computing the range proof over the Pedersen commitment
At this point, we are done with the core of the protocol! However, there are a few problems remaining to address. The most significant of these is the front-running problem we have just unintentionally introduced.
Front-Running: How I Learned to Stop Worrying and Love Being DDOSed
Note that when sending funds, the sender must accurately input their updated balance and sent amount as part of the sigma protocol and range proofs. This introduces a new problem. If another user sends them funds and updates the sender’s balance before the sender’s proof is verified, the proof they just spent time validating is now invalid. In an extreme case, a malicious party could send to our would-be sender a constant stream of transactions, constantly updating their balance and effectively locking them out of their funds with a DDOS attack.
This problem is unsolved in the Veiled Coins module. Solana’s Confidential Transactions solves this by implementing the solution proposed in the Zether paper, which is to split a user’s balance into two balances - available and pending. The available balance does not update when a user receives a transacted amount. This amount rather is deposited into the user’s pending balance, over which proofs are never computed. Either at the user’s prompting, or automatically at pre-defined intervals, the pending balance, before being set to 0, can be homomorphically added to the user’s available balance, making their funds now available for transfer.
Efficient Discrete Logarithms With Assisted Marsupials
The next problem to address is the potential inefficiency of requiring a user to solve a discrete logarithm problem in the size of their balance every time they wish to send a transaction. For smaller 32-bit values, this is fine. At 64-bits, it is tractable, particularly with a specialized algorithm such as the one devised in the 2012 paper Computing small discrete logarithms faster by Bernstein and Lange, which uses a parallelized version of Pollard’s Kangaroo Algorithm to give
The solution implemented by Aptos’ Veiled Coins is to truncate a 64-bit amount by cutting off the highest and lowest 16 bits, to produce a 32-bit value. This works for specific coins where you know in advance that the lowest 16 bits are insignificant enough not to matter much, and that transactions using the highest 16 bits are large enough that they are rarely sent. However, this does produce a strictly worse user experience. In addition, it will not work in a generalized setting which covers multiple types of coin, each of which may have its own decimal point placement and patterns of transaction.
Solana’s Confidential Transfers, interestingly enough, solves this by allowing users to have infinitely large available balance amounts. This is done by additionally requiring a user to symmetrically encrypt their balance whenever they update it. Because symmetric encryption is very efficient regardless of the message size, this dramatically reduces the time needed for a user to access their balance, which may be confirmed by using it to recompute their available balance ciphertext. Presumably the supply of any one token will be smaller than the prime order of the group being used, which additionally prevents overflows.
NOTE: This symmetric encryption hint does introduce one new problem, which is that a software error - or even malicious software - by the API a user accesses to update their balance could cause their symmetric encryption to encrypt the wrong balance value. If their balance is large enough, this will make it impossible for them to decrypt using ElGamal. There is a way to deal with this - the user can still decrypt all sent and received transactions to derive their balance amount. However, if a user has sent and received many transactions this could be fairly time-consuming.
While a user’s pending balance in theory also has no limit, this is restricted by two details: one is that transacted amounts are limited in size by the range proofs detailed above, and another is a cap they have implemented on the number of incoming transactions a user is allowed to receive until they are required to roll their balance over. For example, say that incoming transactions are limited to 32 bits, and the amount of incoming transfers allowed before rolling over is
Confidential Transfers also increase the size of a user’s pending balance by splitting it into one lower bit chunk and one higher bit chunk, to achieve a 48-bit pending balance before overflows occur, correspondingly limiting transferred amounts to 48 bits. In parrticular, they represent 32 higher bits as a twisted ElGamal ciphertext
Key Rotation For Dummies
A user’s private decryption key may be compromised, in which case they will need to rotate it to prevent loss of funds. In addition, the may simply wish to rotate their key regularly as a matter of good security hygiene. In either case they will need to prove that their currently encrypted balance under their previos ElGamal public key encrypts the same amount as their new ElGamal public key, so that given
Conclusion
Overall, the Zether protocol and its spinoffs provide a relatively simple and efficient way to perform confidential transactions in a trustless setting. Confidential Transfers on Solana provides an excellent instantiation of the core idea of Zether while addressing some practical problems around efficient decryption and front-running. Veiled Coins on Aptos provides an interesting toy example useful for educational purposes. However, the code for the latter is is very well written and commented, which makes it excellent for learning, in addition to reducing the likelihood of bugs. I highly recommend giving it a look.