spl_token_2022/extension/confidential_mint_burn/
account_info.rsuse {
super::ConfidentialMintBurn,
crate::error::TokenError,
bytemuck::{Pod, Zeroable},
solana_zk_sdk::{
encryption::{
auth_encryption::{AeCiphertext, AeKey},
elgamal::{ElGamalCiphertext, ElGamalKeypair},
pedersen::PedersenOpening,
pod::{
auth_encryption::PodAeCiphertext,
elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
},
},
zk_elgamal_proof_program::proof_data::CiphertextCiphertextEqualityProofData,
},
};
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
pub struct SupplyAccountInfo {
pub current_supply: PodElGamalCiphertext,
pub decryptable_supply: PodAeCiphertext,
pub supply_elgamal_pubkey: PodElGamalPubkey,
}
impl SupplyAccountInfo {
pub fn new(extension: &ConfidentialMintBurn) -> Self {
Self {
current_supply: extension.confidential_supply,
decryptable_supply: extension.decryptable_supply,
supply_elgamal_pubkey: extension.supply_elgamal_pubkey,
}
}
pub fn decrypt_current_supply(
&self,
aes_key: &AeKey,
elgamal_keypair: &ElGamalKeypair,
) -> Result<u64, TokenError> {
let current_decyptable_supply = AeCiphertext::try_from(self.decryptable_supply)
.map_err(|_| TokenError::MalformedCiphertext)?
.decrypt(aes_key)
.ok_or(TokenError::MalformedCiphertext)?;
let decryptable_supply_ciphertext =
elgamal_keypair.pubkey().encrypt(current_decyptable_supply);
#[allow(clippy::arithmetic_side_effects)]
let supply_delta_ciphertext = decryptable_supply_ciphertext
- ElGamalCiphertext::try_from(self.current_supply)
.map_err(|_| TokenError::MalformedCiphertext)?;
let decryptable_to_current_diff = elgamal_keypair
.secret()
.decrypt_u32(&supply_delta_ciphertext)
.ok_or(TokenError::MalformedCiphertext)?;
current_decyptable_supply
.checked_sub(decryptable_to_current_diff)
.ok_or(TokenError::Overflow)
}
pub fn generate_rotate_supply_elgamal_pubkey_proof(
&self,
aes_key: &AeKey,
current_supply_elgamal_keypair: &ElGamalKeypair,
new_supply_elgamal_keypair: &ElGamalKeypair,
) -> Result<CiphertextCiphertextEqualityProofData, TokenError> {
let current_supply =
self.decrypt_current_supply(aes_key, current_supply_elgamal_keypair)?;
let new_supply_opening = PedersenOpening::new_rand();
let new_supply_ciphertext = new_supply_elgamal_keypair
.pubkey()
.encrypt_with(current_supply, &new_supply_opening);
CiphertextCiphertextEqualityProofData::new(
current_supply_elgamal_keypair,
new_supply_elgamal_keypair.pubkey(),
&self
.current_supply
.try_into()
.map_err(|_| TokenError::MalformedCiphertext)?,
&new_supply_ciphertext,
&new_supply_opening,
current_supply,
)
.map_err(|_| TokenError::ProofGeneration)
}
}