Open abcalphabet opened 5 months ago
Thanks for a great write-up and a draft PR! Looks really good and I agree that this is a well-motivated extension.
Let me just add some details regarding the proof data and the proof verification instructions we would need from the new zk-elgamal-proof-program at least for my own reference.
The confidential mint instruction would require two grouped ElGamal ciphertexts with 3 handles, which will encrypt the low and high bits of the mint amount under the destination ElGamal public key, the auditor's ElGamal public key, and the supply authority ElGamal public key.
In the same transaction (or using proof contexts), we would need to have the following proof verification instructions:
VerifyBatchedGroupedCiphertext3HandlesValidity
- to prove that the grouped ciphertexts above is properly generatedVerifyBatchedRangeProofU64
- to prove that the mint amount satisfies the 48-bit boundThe confidential burn instruction would require a regular ElGamal ciphertext and a grouped ElGamal ciphertext with 3 handles.
In the same transaction (or using proof contexts), we would need to have the following proof verification instructions:
VerifyGroupedCiphertext3HandlesValidity
- to prove that the grouped ciphertext above is properly generatedVerifyCiphertextCommitmentEquality
- the randomness is not known for the ElGamal ciphertext encrypting the remaining balance and hence, we have to generate a new Pedersen commitment in order to apply range proof on the ciphertext. VerifyBatchedRangeProofU128
- to prove that the remaining balance is non-negative (an unsigned 64-bit number) and the burn amount is a 64-bit number.Some subtlety's might come up as we implement the proof generation, so I will edit this page as we proceed with the implementation.
To address the issue of the authority needing to decrypt the ciphertexts in each of the mint and burn instructions to calculate the supply of the token, we can also consider having an encrypted supply in the mint extension under the auditor's ElGamal public key. Each confidential mint and burn instructions contain the amounts encrypted under the auditor's public key, so the processor logic could simply add/subtract these ciphertexts to/from the encrypted supply associated with the mint. Have you thought about this direction?
I think the only real disadvantage would be a trade-off in performance. It would be easier to keep track of the supply, but in exchange, every confidential mint and burn instruction would require a write-lock on the mint (and zkp is a relatively heavy operation).
Regarding the performance issues of adding an encrypted supply: The write lock should be less of an issue when the proofs are generated and persisted into context state accounts prior to sending the actual mint/burn transactions, right? Or are the syscall::{subtract_with_lo_hi, add}
calls that expensive by themselves?
One potential issue I see with tracking a confidential supply via a single ElGamalCipherText
is also that the decryption of the actual supply might become problematic. As I understand it the decryption of larger ElGamal encrypted u64 values is computationally more or less impossible, correct?
If we track the supply via the 32 high & low bits which additional proofs would we require in your opinion? Is a simple range proof to show that the resulting supply is non-negative / a 64-bit int be enough? Since both mint & burn already include ciphertext validity proofs for the auditor amount.
Regarding the performance issues of adding an encrypted supply: The write lock should be less of an issue when the proofs are generated and persisted into context state accounts prior to sending the actual mint/burn transactions, right? Or are the
syscall::{subtract_with_lo_hi, add}
calls that expensive by themselves?
Yeah if context state accounts are used, then the write-lock is not really much of an issue. When the zk program is activated, the use of context state accounts is really going to be the only way to use confidential transfers until the transaction size limit are increased. All in all, I agree that the write-lock is not going to be a major issue.
One potential issue I see with tracking a confidential supply via a single
ElGamalCipherText
is also that the decryption of the actual supply might become problematic. As I understand it the decryption of larger ElGamal encrypted u64 values is computationally more or less impossible, correct?
This is a good point. Directly decrypting from ElGamal ciphertexts is quite expensive, but it does scale with the size of the pre-computation table the decryptor has access to. In the worst case, if the decryption becomes too expensive, the authority can always use the mint and burn transactions to decrypt the supply as originally proposed.
The only real cost to adding to the encrypted supply in the mint is
I think 64 bytes in the mint is pretty trivial. The second/third issues are also not major, but one way to address them could be to have Option<ElGamalCiphertext>
in the mint instead so that different mints can choose depending on their supply.
If we track the supply via the 32 high & low bits which additional proofs would we require in your opinion? Is a simple range proof to show that the resulting supply is non-negative / a 64-bit int be enough? Since both mint & burn already include ciphertext validity proofs for the auditor amount.
I realized that the way I wrote the confidential burn above, I did not divide the burn amount into low and high bits, which I should correct. The burn amount should be divided into low and high bits and then encrypted. It will require a VerifyBatchedGroupedCiphertext2HandlesValidity
instruction as well.
But in addition to the correction above, there shouldn't really be any additional proof needed. The only issue with dividing the supply into low and high components is that the low ciphertext could easily overflow. We can add an instruction that re-shuffles the overflown amount into the high ciphertext, but this will require an additional instruction with zkp, so I am not sure if this additional complexity is worth having.
I think 64 bytes in the mint is pretty trivial. The second/third issues are also not major, but one way to address them could be to have Option
in the mint instead so that different mints can choose depending on their supply.
Making the supply optional might actually be somewhat tricky, for OptionalNonZeroElGamalPubkey
s the none/some check is done by checking the inside of the pod against the zeroed value, which would be a perfectly legitimate state for a fresh mint with zero supply. I think the CUs and write-locking also aren't that much of an issue, considering the proofs required prior to a mint / burn there shouldn't be that legitimate mint and burn transactions per block anyways.
One thing to consider is whether it makes sense to make the write lock / computations dependent on the mint's auditor pubkey being nonzero, since without the auditor pubkey the ciphertexts to update the supply can't be generated. Though again I'm not sure whether those would actually be enough of an issue to justify the additional complexity.
Actually, I don't think the auditor pubkey should be used for the supply, since the auditor pubkey can always just be exchanged which would break the supply ciphertext.
I think it makes sense to add a supply_elgamal_pubkey
to the mints data (another 32 bytes) and use that exclusively for the supply ciphertext. This would change the mint / burn ciphertext validity proofs to VerifyBatchedGroupedCiphertext3HandlesValidity
.
Adding the additional pubkey would then also make updating the mint a bit more complex. If we want to allow for the rotation of this supply_elgamal_pubkey
, any update would also need to rotate the confidential_supply
ciphertext, providing a CiphertextCiphertextEqualityProof
that the old and new encrypt the same value. With that we shouldn't need any additional proofs, since the validity of the old supply ciphertext is proven any time it's updated.
Making the supply optional might actually be somewhat tricky, for OptionalNonZeroElGamalPubkeys the none/some check is done by checking the inside of the pod against the zeroed value, which would be a perfectly legitimate state for a fresh mint with zero supply. I think the CUs and write-locking also aren't that much of an issue, considering the proofs required prior to a mint / burn there shouldn't be that legitimate mint and burn transactions per block anyways.
Yeah this is good point. We can require the ciphertext to always be the non-zero ciphertext. The probability that a properly (randomly) generated ciphertext is all-zero should be pretty much zero. When initializing the mint, we can require the initial encrypted supply to be a randomly generated encryption of 0 and also require VerifyZeroCiphertext
instruction
But all in all, maybe this is an unnecessary complexity for relatively minor issues with write-lock and CUs. Perhaps we can just always have encrypted supply for any mint with the extension.
One thing to consider is whether it makes sense to make the write lock / computations dependent on the mint's auditor pubkey being nonzero, since without the auditor pubkey the ciphertexts to update the supply can't be generated. Though again I'm not sure whether those would actually be enough of an issue to justify the additional complexity.
This is a good point as well. I was thinking that for confidential mint/burn extension, we would always require the auditor pubkey, but perhaps having a separate supply_elgamal_pubkey
is cleaner.
It is worth noting that functionally speaking, the auditor ElGamal keypair is at least as powerful as the supply ElGamal keypair since it can be used to decrypt each mint and burn transactions (remember that the encrypted supply is more for convenience). In fact, it is strictly more powerful in that a supply ElGamal keypair can only be used to decrypt mint/burn tx's, but not transfer tx's. But this does seem point to the need for having a separate supply_elgamal_pubkey
since there could be situations where we want confidential mint/burn, but we don't want the mint/burn authority or any other entity to be able to decrypt confidential transfers.
Adding the additional pubkey would then also make updating the mint a bit more complex. If we want to allow for the rotation of this supply_elgamal_pubkey, any update would also need to rotate the confidential_supply ciphertext, providing a CiphertextCiphertextEqualityProof that the old and new encrypt the same value. With that we shouldn't need any additional proofs, since the validity of the old supply ciphertext is proven any time it's updated.
Rotating keypairs in general (not just in the context of confidential mint/burn) is a tricky issue though. Even if something like the auditor or supply keypair is rotated, the original key has to be kept around because the old tx's can only be decrypted with the original keypair. This is just something that is inherent with any protocol of this kind.
Proposed feature
Token-2022 adds the token-extension of confidential transfers. In order to increase or decrease the supply of a token in the confidential balance space the tokens have to be first minted normally and then deposited into the confidential balance for the former and withdrawn from the confidential balance and then burned in the unencrypted balance space for the latter.
If the purpose of a token is to only operate in the confidential balance space, it should be possible to skip the deposit and withdraw steps and directly mint into or burn out of the confidential balance.
Why is this needed
One possible application confidential token balances is the representation of RWAs via a token. At Iron we’re using Token Extensions to issue tokenized bank deposits which comes with a wide range of regulatory requirements. In this more regulated environment there are two relevant considerations to minting and burning confidentially:
The currently available functionality of going via the unencrypted space to change the supply goes against point 1 as on on each inflow tokens have to be minted without encryption and then deposited into the confidential balance of the token account. An alternative to this would be to premint a large amount of tokens into a "treasury" account and then send those out confidentially as inflows happen, this would however obviously be in violation of point 2. The issue for burns is similar with either burning unencrypted to trigger / represent an outflow or sending the tokens back to a pooled account instead of that.
Proposed solution
A
confidential-mint-burn
extension adding aConfindentialMint
and aConfidentialBurn
instruction. This extension would add a separate mint-authority used for minting confidential tokens to the token's mint account.The
ConfindentialMint
instruction can reuse most of theDeposit
logic to add tokens to the confidential balance, but requires an additional proof that the suppliedElGamalCiphertext
s represent a 48-bit number, so as to properly fit intopending_balance_hi
andpending_balance_lo
.The
ConfidentialBurn
can also reuse some existing code, but that of theTransfer
instead of theWithdraw
instruction. To achieve a confidential burn, and guarantee correctness of the confidential balance before / after the burn, the source-side logic of the transfer can be used. This provides a simple way of generating the correct proofs and applying them in a proven way. The destination side of the logic and proofs would obviously not be used, as a burn can be represented as a transfer to /dev/null.Other considerations
One issue with the above approach is that the supply of the token would not be available on the mint account anymore, but only attainable by going through all mint and burn transactions and deciphering amount / summing with the auditor elgamal-keypair.
In order for the extension to not have side-effects on the unencrypted balance space the activation of this extension would disable the
Deposit
andWithdraw
instructions of theconfidential-transfer
extension.Another option would be to add a confidential supply to the
confidential-mint-burn
extension and track the supply there, this would likely be a significant effort though, requiring additional proof logic to guarantee correctness of said confidential supply.