diff --git a/token/program-2022/src/extension/confidential_mint_burn/account_info.rs b/token/program-2022/src/extension/confidential_mint_burn/account_info.rs index 772355af016..63ba4eb61b8 100644 --- a/token/program-2022/src/extension/confidential_mint_burn/account_info.rs +++ b/token/program-2022/src/extension/confidential_mint_burn/account_info.rs @@ -1,11 +1,16 @@ use { super::ConfidentialMintBurn, - crate::error::TokenError, + crate::{ + error::TokenError, + extension::confidential_transfer::{ + ConfidentialTransferAccount, DecryptableBalance, EncryptedBalance, + }, + }, bytemuck::{Pod, Zeroable}, solana_zk_sdk::{ encryption::{ auth_encryption::{AeCiphertext, AeKey}, - elgamal::{ElGamalCiphertext, ElGamalKeypair}, + elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey}, pedersen::PedersenOpening, pod::{ auth_encryption::PodAeCiphertext, @@ -14,6 +19,10 @@ use { }, zk_elgamal_proof_program::proof_data::CiphertextCiphertextEqualityProofData, }, + spl_token_confidential_transfer_proof_generation::{ + burn::{burn_split_proof_data, BurnProofData}, + mint::{mint_split_proof_data, MintProofData}, + }, }; /// Confidential Mint Burn extension information needed to construct a @@ -102,4 +111,98 @@ impl SupplyAccountInfo { ) .map_err(|_| TokenError::ProofGeneration) } + + /// Create a mint proof data that is split into equality, ciphertext + /// validity, and range proof. + pub fn generate_split_mint_proof_data( + &self, + mint_amount: u64, + current_supply: u64, + supply_elgamal_keypair: &ElGamalKeypair, + destination_elgamal_pubkey: &ElGamalPubkey, + auditor_elgamal_pubkey: Option<&ElGamalPubkey>, + ) -> Result { + let current_supply_ciphertext = self + .current_supply + .try_into() + .map_err(|_| TokenError::MalformedCiphertext)?; + + mint_split_proof_data( + ¤t_supply_ciphertext, + mint_amount, + current_supply, + supply_elgamal_keypair, + destination_elgamal_pubkey, + auditor_elgamal_pubkey, + ) + .map_err(|e| -> TokenError { e.into() }) + } + + /// Compute the new decryptable supply. + pub fn new_decryptable_supply( + &self, + mint_amount: u64, + aes_key: &AeKey, + elgamal_keypair: &ElGamalKeypair, + ) -> Result { + let current_decrypted_supply = self.decrypt_current_supply(aes_key, elgamal_keypair)?; + let new_decrypted_available_balance = current_decrypted_supply + .checked_add(mint_amount) + .ok_or(TokenError::Overflow)?; + + Ok(aes_key.encrypt(new_decrypted_available_balance)) + } +} + +/// Confidential Mint Burn extension information needed to construct a +/// `Burn` instruction. +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] +pub struct BurnAccountInfo { + /// The available balance (encrypted by `encryption_pubkey`) + pub available_balance: EncryptedBalance, + /// The decryptable available balance + pub decryptable_available_balance: DecryptableBalance, +} + +impl BurnAccountInfo { + /// Create the `ApplyPendingBalance` instruction account information from + /// `ConfidentialTransferAccount`. + pub fn new(account: &ConfidentialTransferAccount) -> Self { + Self { + available_balance: account.available_balance, + decryptable_available_balance: account.decryptable_available_balance, + } + } + + /// Create a burn proof data that is split into equality, ciphertext + /// validity, and range proof. + pub fn generate_split_burn_proof_data( + &self, + burn_amount: u64, + source_elgamal_keypair: &ElGamalKeypair, + aes_key: &AeKey, + auditor_elgamal_pubkey: Option<&ElGamalPubkey>, + supply_elgamal_pubkey: &ElGamalPubkey, + ) -> Result { + let current_available_balance_ciphertext = self + .available_balance + .try_into() + .map_err(|_| TokenError::MalformedCiphertext)?; + let current_decryptable_available_balance = self + .decryptable_available_balance + .try_into() + .map_err(|_| TokenError::MalformedCiphertext)?; + + burn_split_proof_data( + ¤t_available_balance_ciphertext, + ¤t_decryptable_available_balance, + burn_amount, + source_elgamal_keypair, + aes_key, + auditor_elgamal_pubkey, + supply_elgamal_pubkey, + ) + .map_err(|e| -> TokenError { e.into() }) + } }