Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Proposal: Confidential Mint & Burn Extension #6879

Open
abcalphabet opened this issue Jun 19, 2024 · 7 comments
Open

Feature Proposal: Confidential Mint & Burn Extension #6879

abcalphabet opened this issue Jun 19, 2024 · 7 comments

Comments

@abcalphabet
Copy link

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:

  1. Only the issuer should be able to discern (and share with authorities when necessary) the balance and transaction amounts of individual holders
  2. The supply of the token should always represent the amount of the RWA held, i.e. mint on inflows and burn on outflows

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 a ConfindentialMint and a ConfidentialBurn 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 the Deposit logic to add tokens to the confidential balance, but requires an additional proof that the supplied ElGamalCiphertexts represent a 48-bit number, so as to properly fit into pending_balance_hi and pending_balance_lo.

The ConfidentialBurn can also reuse some existing code, but that of the Transfer instead of the Withdraw 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 and Withdraw instructions of the confidential-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.

@samkim-crypto
Copy link
Contributor

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.

Confidential Mint

The confidential mint instruction would require two grouped ElGamal ciphertexts with 2 handles, which will encrypt the low and high bits of the mint amount under the destination ElGamal public key and the auditor's ElGamal public key.

In the same transaction (or using proof contexts), we would need to have the following proof verification instructions:

  • VerifyBatchedGroupedCiphertext2HandlesValidity - to prove that the grouped ciphertexts above is properly generated
  • VerifyBatchedRangeProofU64 - to prove that the mint amount satisfies the 48-bit bound

Confidential Burn

The confidential burn instruction would require a regular ElGamal ciphertext and a grouped ElGamal ciphertext with 2 handles.

  • The regular ElGamal ciphertext encrypts the remaining balance in the account
  • The grouped ElGamal ciphertext encrypts the burn amount under the source ElGamal public key and the auditor's ElGamal public key.

In the same transaction (or using proof contexts), we would need to have the following proof verification instructions:

  • VerifyGroupedCiphertext2HandlesValidity - to prove that the grouped ciphertext above is properly generated
  • VerifyCiphertextCommitmentEquality - 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.

@samkim-crypto
Copy link
Contributor

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).

@abcalphabet
Copy link
Author

abcalphabet commented Jul 2, 2024

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.

@samkim-crypto
Copy link
Contributor

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

  1. The mint size increases by 64 bytes
  2. Need for write-lock on the mint
  3. Each confidential mint/burn instructions will use syscalls to add/subtract from the mint, which will take additional CU's

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.

@abcalphabet
Copy link
Author

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 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.

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.

@abcalphabet
Copy link
Author

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.

@samkim-crypto
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants