[confidential-extension] Use `OptionalNonZeroPubkey` and `OptionalNonZeroEncryptionPubkey` for confidential extension (#3943)

* use OptionalNonZeroPubkey for the confidential mint authority pubkey

* add OptionalNonZeroEncryptionPubkey

* update tests

* Update token/program-2022/src/pod.rs

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>

* remove unnecessary COption convertion for OptionalNonZeroEncryptionPubkey

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
This commit is contained in:
samkim-crypto 2022-12-23 11:06:18 +09:00 committed by GitHub
parent 19b8fae56c
commit b9aba3fb8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 263 additions and 184 deletions

View File

@ -20,11 +20,12 @@ use {
}, },
spl_token_2022::{ spl_token_2022::{
extension::{ extension::{
confidential_transfer, confidential_transfer::EncryptionPubkey, cpi_guard, confidential_transfer, cpi_guard, default_account_state, interest_bearing_mint,
default_account_state, interest_bearing_mint, memo_transfer, transfer_fee, memo_transfer, transfer_fee, BaseStateWithExtensions, ExtensionType,
BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned, StateWithExtensionsOwned,
}, },
instruction, instruction,
pod::EncryptionPubkey,
solana_zk_token_sdk::{ solana_zk_token_sdk::{
encryption::{auth_encryption::*, elgamal::*}, encryption::{auth_encryption::*, elgamal::*},
errors::ProofError, errors::ProofError,
@ -106,8 +107,8 @@ pub enum ExtensionInitializationParams {
ConfidentialTransferMint { ConfidentialTransferMint {
authority: Option<Pubkey>, authority: Option<Pubkey>,
auto_approve_new_accounts: bool, auto_approve_new_accounts: bool,
auditor_encryption_pubkey: EncryptionPubkey, auditor_encryption_pubkey: Option<EncryptionPubkey>,
withdraw_withheld_authority_encryption_pubkey: EncryptionPubkey, withdraw_withheld_authority_encryption_pubkey: Option<EncryptionPubkey>,
}, },
DefaultAccountState { DefaultAccountState {
state: AccountState, state: AccountState,
@ -158,10 +159,10 @@ impl ExtensionInitializationParams {
} => confidential_transfer::instruction::initialize_mint( } => confidential_transfer::instruction::initialize_mint(
token_program_id, token_program_id,
mint, mint,
authority.as_ref(), authority,
auto_approve_new_accounts, auto_approve_new_accounts,
&auditor_encryption_pubkey, auditor_encryption_pubkey,
&withdraw_withheld_authority_encryption_pubkey, withdraw_withheld_authority_encryption_pubkey,
), ),
Self::DefaultAccountState { state } => { Self::DefaultAccountState { state } => {
default_account_state::instruction::initialize_default_account_state( default_account_state::instruction::initialize_default_account_state(
@ -1492,7 +1493,7 @@ where
authority: &S, authority: &S,
new_authority: Option<&S>, new_authority: Option<&S>,
auto_approve_new_account: bool, auto_approve_new_account: bool,
auditor_encryption_pubkey: &EncryptionPubkey, auditor_encryption_pubkey: Option<EncryptionPubkey>,
) -> TokenResult<T::Output> { ) -> TokenResult<T::Output> {
let mut signers = vec![authority]; let mut signers = vec![authority];
let new_authority_pubkey = if let Some(new_authority) = new_authority { let new_authority_pubkey = if let Some(new_authority) = new_authority {
@ -1789,16 +1790,20 @@ where
/// Fetch the ElGamal pubkey key of the auditor associated with a confidential token mint /// Fetch the ElGamal pubkey key of the auditor associated with a confidential token mint
pub async fn confidential_transfer_get_auditor_encryption_pubkey<S: Signer>( pub async fn confidential_transfer_get_auditor_encryption_pubkey<S: Signer>(
&self, &self,
) -> TokenResult<ElGamalPubkey> { ) -> TokenResult<Option<ElGamalPubkey>> {
let mint_state = self.get_mint_info().await.unwrap(); let mint_state = self.get_mint_info().await.unwrap();
let ct_mint = let ct_mint =
mint_state.get_extension::<confidential_transfer::ConfidentialTransferMint>()?; mint_state.get_extension::<confidential_transfer::ConfidentialTransferMint>()?;
let auditor_pubkey = ct_mint let auditor_encryption_pubkey: Option<EncryptionPubkey> =
.auditor_encryption_pubkey ct_mint.auditor_encryption_pubkey.into();
.try_into()
.map_err(TokenError::Proof)?;
Ok(auditor_pubkey) if let Some(encryption_pubkey) = auditor_encryption_pubkey {
let encryption_pubkey: ElGamalPubkey =
encryption_pubkey.try_into().map_err(TokenError::Proof)?;
Ok(Some(encryption_pubkey))
} else {
Ok(None)
}
} }
/// Fetch the ElGamal pubkey key of the withdraw withheld authority associated with a /// Fetch the ElGamal pubkey key of the withdraw withheld authority associated with a
@ -1807,16 +1812,20 @@ where
S: Signer, S: Signer,
>( >(
&self, &self,
) -> TokenResult<ElGamalPubkey> { ) -> TokenResult<Option<ElGamalPubkey>> {
let mint_state = self.get_mint_info().await.unwrap(); let mint_state = self.get_mint_info().await.unwrap();
let ct_mint = let ct_mint =
mint_state.get_extension::<confidential_transfer::ConfidentialTransferMint>()?; mint_state.get_extension::<confidential_transfer::ConfidentialTransferMint>()?;
let auditor_pubkey = ct_mint let withdraw_withheld_authority_encryption_pubkey: Option<EncryptionPubkey> =
.withdraw_withheld_authority_encryption_pubkey ct_mint.withdraw_withheld_authority_encryption_pubkey.into();
.try_into()
.map_err(TokenError::Proof)?;
Ok(auditor_pubkey) if let Some(encryption_pubkey) = withdraw_withheld_authority_encryption_pubkey {
let encryption_pubkey: ElGamalPubkey =
encryption_pubkey.try_into().map_err(TokenError::Proof)?;
Ok(Some(encryption_pubkey))
} else {
Ok(None)
}
} }
/// Deposit SPL Tokens into the pending balance of a confidential token account /// Deposit SPL Tokens into the pending balance of a confidential token account
@ -1932,7 +1941,7 @@ where
source_available_balance: u64, source_available_balance: u64,
source_available_balance_ciphertext: &ElGamalCiphertext, source_available_balance_ciphertext: &ElGamalCiphertext,
destination_elgamal_pubkey: &ElGamalPubkey, destination_elgamal_pubkey: &ElGamalPubkey,
auditor_elgamal_pubkey: &ElGamalPubkey, auditor_elgamal_pubkey: Option<ElGamalPubkey>,
) -> TokenResult<T::Output> { ) -> TokenResult<T::Output> {
let source_elgamal_keypair = let source_elgamal_keypair =
ElGamalKeypair::new(source_token_authority, source_token_account) ElGamalKeypair::new(source_token_authority, source_token_account)
@ -1966,7 +1975,7 @@ where
source_available_balance: u64, source_available_balance: u64,
source_available_balance_ciphertext: &ElGamalCiphertext, source_available_balance_ciphertext: &ElGamalCiphertext,
destination_elgamal_pubkey: &ElGamalPubkey, destination_elgamal_pubkey: &ElGamalPubkey,
auditor_elgamal_pubkey: &ElGamalPubkey, auditor_elgamal_pubkey: Option<ElGamalPubkey>,
source_elgamal_keypair: &ElGamalKeypair, source_elgamal_keypair: &ElGamalKeypair,
source_authenticated_encryption_key: &AeKey, source_authenticated_encryption_key: &AeKey,
) -> TokenResult<T::Output> { ) -> TokenResult<T::Output> {
@ -1974,6 +1983,8 @@ where
return Err(TokenError::MaximumDepositTransferAmountExceeded); return Err(TokenError::MaximumDepositTransferAmountExceeded);
} }
let auditor_elgamal_pubkey = auditor_elgamal_pubkey.unwrap_or_default();
let proof_data = confidential_transfer::instruction::TransferData::new( let proof_data = confidential_transfer::instruction::TransferData::new(
amount, amount,
( (
@ -1981,7 +1992,7 @@ where
source_available_balance_ciphertext, source_available_balance_ciphertext,
), ),
source_elgamal_keypair, source_elgamal_keypair,
(destination_elgamal_pubkey, auditor_elgamal_pubkey), (destination_elgamal_pubkey, &auditor_elgamal_pubkey),
) )
.map_err(TokenError::Proof)?; .map_err(TokenError::Proof)?;
@ -2019,7 +2030,7 @@ where
source_available_balance: u64, source_available_balance: u64,
source_available_balance_ciphertext: &ElGamalCiphertext, source_available_balance_ciphertext: &ElGamalCiphertext,
destination_elgamal_pubkey: &ElGamalPubkey, destination_elgamal_pubkey: &ElGamalPubkey,
auditor_elgamal_pubkey: &ElGamalPubkey, auditor_elgamal_pubkey: Option<ElGamalPubkey>,
withdraw_withheld_authority_elgamal_pubkey: &ElGamalPubkey, withdraw_withheld_authority_elgamal_pubkey: &ElGamalPubkey,
epoch_info: &EpochInfo, epoch_info: &EpochInfo,
) -> TokenResult<T::Output> { ) -> TokenResult<T::Output> {
@ -2057,7 +2068,7 @@ where
source_available_balance: u64, source_available_balance: u64,
source_available_balance_ciphertext: &ElGamalCiphertext, source_available_balance_ciphertext: &ElGamalCiphertext,
destination_elgamal_pubkey: &ElGamalPubkey, destination_elgamal_pubkey: &ElGamalPubkey,
auditor_elgamal_pubkey: &ElGamalPubkey, auditor_elgamal_pubkey: Option<ElGamalPubkey>,
withdraw_withheld_authority_elgamal_pubkey: &ElGamalPubkey, withdraw_withheld_authority_elgamal_pubkey: &ElGamalPubkey,
source_elgamal_keypair: &ElGamalKeypair, source_elgamal_keypair: &ElGamalKeypair,
source_authenticated_encryption_key: &AeKey, source_authenticated_encryption_key: &AeKey,
@ -2067,7 +2078,8 @@ where
return Err(TokenError::MaximumDepositTransferAmountExceeded); return Err(TokenError::MaximumDepositTransferAmountExceeded);
} }
// TODO: take transfer fee params as input let auditor_elgamal_pubkey = auditor_elgamal_pubkey.unwrap_or_default();
let mint_state = self.get_mint_info().await.unwrap(); let mint_state = self.get_mint_info().await.unwrap();
let transfer_fee_config = mint_state let transfer_fee_config = mint_state
.get_extension::<transfer_fee::TransferFeeConfig>() .get_extension::<transfer_fee::TransferFeeConfig>()
@ -2081,7 +2093,7 @@ where
source_available_balance_ciphertext, source_available_balance_ciphertext,
), ),
source_elgamal_keypair, source_elgamal_keypair,
(destination_elgamal_pubkey, auditor_elgamal_pubkey), (destination_elgamal_pubkey, &auditor_elgamal_pubkey),
FeeParameters { FeeParameters {
fee_rate_basis_points: u16::from(fee_parameters.transfer_fee_basis_points), fee_rate_basis_points: u16::from(fee_parameters.transfer_fee_basis_points),
maximum_fee: u64::from(fee_parameters.maximum_fee), maximum_fee: u64::from(fee_parameters.maximum_fee),

View File

@ -17,6 +17,7 @@ use {
}, },
BaseStateWithExtensions, ExtensionType, BaseStateWithExtensions, ExtensionType,
}, },
pod::EncryptionPubkey,
solana_zk_token_sdk::{ solana_zk_token_sdk::{
encryption::{auth_encryption::*, elgamal::*}, encryption::{auth_encryption::*, elgamal::*},
zk_token_elgamal::pod::Zeroable, zk_token_elgamal::pod::Zeroable,
@ -53,9 +54,7 @@ fn test_epoch_info() -> EpochInfo {
struct ConfidentialTransferMintWithKeypairs { struct ConfidentialTransferMintWithKeypairs {
ct_mint: ConfidentialTransferMint, ct_mint: ConfidentialTransferMint,
ct_mint_authority: Keypair, ct_mint_authority: Keypair,
#[allow(dead_code)]
ct_mint_transfer_auditor_encryption_keypair: ElGamalKeypair, ct_mint_transfer_auditor_encryption_keypair: ElGamalKeypair,
#[allow(dead_code)]
ct_mint_withdraw_withheld_authority_encryption_keypair: ElGamalKeypair, ct_mint_withdraw_withheld_authority_encryption_keypair: ElGamalKeypair,
} }
@ -63,15 +62,28 @@ impl ConfidentialTransferMintWithKeypairs {
fn new() -> Self { fn new() -> Self {
let ct_mint_authority = Keypair::new(); let ct_mint_authority = Keypair::new();
let ct_mint_transfer_auditor_encryption_keypair = ElGamalKeypair::new_rand(); let ct_mint_transfer_auditor_encryption_keypair = ElGamalKeypair::new_rand();
let ct_mint_transfer_auditor_encryption_pubkey: EncryptionPubkey =
ct_mint_transfer_auditor_encryption_keypair
.public
.try_into()
.unwrap();
let ct_mint_withdraw_withheld_authority_encryption_keypair = ElGamalKeypair::new_rand(); let ct_mint_withdraw_withheld_authority_encryption_keypair = ElGamalKeypair::new_rand();
let ct_mint_withdraw_withheld_authority_encryption_pubkey: EncryptionPubkey =
ct_mint_withdraw_withheld_authority_encryption_keypair
.public
.try_into()
.unwrap();
let ct_mint = ConfidentialTransferMint { let ct_mint = ConfidentialTransferMint {
authority: ct_mint_authority.pubkey(), authority: Some(ct_mint_authority.pubkey()).try_into().unwrap(),
auto_approve_new_accounts: true.into(), auto_approve_new_accounts: true.into(),
auditor_encryption_pubkey: ct_mint_transfer_auditor_encryption_keypair.public.into(), auditor_encryption_pubkey: Some(ct_mint_transfer_auditor_encryption_pubkey)
withdraw_withheld_authority_encryption_pubkey: .try_into()
ct_mint_withdraw_withheld_authority_encryption_keypair .unwrap(),
.public withdraw_withheld_authority_encryption_pubkey: Some(
.into(), ct_mint_withdraw_withheld_authority_encryption_pubkey,
)
.try_into()
.unwrap(),
withheld_amount: EncryptedWithheldAmount::zeroed(), withheld_amount: EncryptedWithheldAmount::zeroed(),
}; };
Self { Self {
@ -286,11 +298,12 @@ async fn ct_initialize_and_update_mint() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -305,7 +318,7 @@ async fn ct_initialize_and_update_mint() {
// Change the authority // Change the authority
let new_ct_mint_authority = Keypair::new(); let new_ct_mint_authority = Keypair::new();
let new_ct_mint = ConfidentialTransferMint { let new_ct_mint = ConfidentialTransferMint {
authority: new_ct_mint_authority.pubkey(), authority: Some(new_ct_mint_authority.pubkey()).try_into().unwrap(),
..ConfidentialTransferMint::default() ..ConfidentialTransferMint::default()
}; };
@ -314,10 +327,9 @@ async fn ct_initialize_and_update_mint() {
&wrong_keypair, &wrong_keypair,
Some(&new_ct_mint_authority), Some(&new_ct_mint_authority),
new_ct_mint.auto_approve_new_accounts.into(), new_ct_mint.auto_approve_new_accounts.into(),
&new_ct_mint new_ct_mint
.withdraw_withheld_authority_encryption_pubkey .withdraw_withheld_authority_encryption_pubkey
.try_into() .into(),
.unwrap(),
) )
.await .await
.unwrap_err(); .unwrap_err();
@ -332,10 +344,9 @@ async fn ct_initialize_and_update_mint() {
&ct_mint_authority, &ct_mint_authority,
Some(&new_ct_mint_authority), Some(&new_ct_mint_authority),
new_ct_mint.auto_approve_new_accounts.into(), new_ct_mint.auto_approve_new_accounts.into(),
&new_ct_mint new_ct_mint
.withdraw_withheld_authority_encryption_pubkey .withdraw_withheld_authority_encryption_pubkey
.try_into() .into(),
.unwrap(),
) )
.await .await
.unwrap(); .unwrap();
@ -364,10 +375,9 @@ async fn ct_initialize_and_update_mint() {
&new_ct_mint_authority, &new_ct_mint_authority,
None, None,
new_ct_mint.auto_approve_new_accounts.into(), new_ct_mint.auto_approve_new_accounts.into(),
&new_ct_mint new_ct_mint
.withdraw_withheld_authority_encryption_pubkey .withdraw_withheld_authority_encryption_pubkey
.try_into() .into(),
.unwrap(),
) )
.await .await
.unwrap(); .unwrap();
@ -402,11 +412,12 @@ async fn ct_configure_token_account() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -479,11 +490,12 @@ async fn ct_enable_disable_confidential_credits() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -527,11 +539,12 @@ async fn ct_enable_disable_non_confidential_credits() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -624,11 +637,12 @@ async fn ct_new_account_is_empty() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -652,11 +666,12 @@ async fn ct_deposit() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -782,11 +797,12 @@ async fn ct_withdraw() {
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -885,17 +901,21 @@ async fn ct_withdraw() {
#[cfg(feature = "zk-ops")] #[cfg(feature = "zk-ops")]
#[tokio::test] #[tokio::test]
async fn ct_transfer() { async fn ct_transfer() {
let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = let ConfidentialTransferMintWithKeypairs {
ConfidentialTransferMintWithKeypairs::new(); ct_mint,
ct_mint_transfer_auditor_encryption_keypair,
..
} = ConfidentialTransferMintWithKeypairs::new();
let mut context = TestContext::new().await; let mut context = TestContext::new().await;
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -932,7 +952,7 @@ async fn ct_transfer() {
42, 42,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&alice_meta.elgamal_keypair.public, &alice_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap(); .unwrap();
@ -967,7 +987,7 @@ async fn ct_transfer() {
42, 42,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&alice_meta.elgamal_keypair.public, &alice_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap(); .unwrap();
@ -1001,7 +1021,7 @@ async fn ct_transfer() {
0, 0,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&alice_meta.elgamal_keypair.public, &alice_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap_err(); .unwrap_err();
@ -1052,7 +1072,7 @@ async fn ct_transfer() {
42, 42,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap(); .unwrap();
@ -1122,8 +1142,12 @@ async fn ct_transfer() {
#[cfg(feature = "zk-ops")] #[cfg(feature = "zk-ops")]
#[tokio::test] #[tokio::test]
async fn ct_transfer_with_fee() { async fn ct_transfer_with_fee() {
let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = let ConfidentialTransferMintWithKeypairs {
ConfidentialTransferMintWithKeypairs::new(); ct_mint,
ct_mint_transfer_auditor_encryption_keypair,
ct_mint_withdraw_withheld_authority_encryption_keypair,
..
} = ConfidentialTransferMintWithKeypairs::new();
let mut context = TestContext::new().await; let mut context = TestContext::new().await;
context context
@ -1135,11 +1159,12 @@ async fn ct_transfer_with_fee() {
maximum_fee: TEST_MAXIMUM_FEE, maximum_fee: TEST_MAXIMUM_FEE,
}, },
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -1179,7 +1204,7 @@ async fn ct_transfer_with_fee() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&alice_meta.elgamal_keypair.public, &alice_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap(); .unwrap();
@ -1214,7 +1239,7 @@ async fn ct_transfer_with_fee() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&alice_meta.elgamal_keypair.public, &alice_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap(); .unwrap();
@ -1265,11 +1290,8 @@ async fn ct_transfer_with_fee() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
&ct_mint &ct_mint_withdraw_withheld_authority_encryption_keypair.public,
.withdraw_withheld_authority_encryption_pubkey
.try_into()
.unwrap(),
&epoch_info, &epoch_info,
) )
.await .await
@ -1343,6 +1365,7 @@ async fn ct_transfer_with_fee() {
async fn ct_withdraw_withheld_tokens_from_mint() { async fn ct_withdraw_withheld_tokens_from_mint() {
let ConfidentialTransferMintWithKeypairs { let ConfidentialTransferMintWithKeypairs {
ct_mint, ct_mint,
ct_mint_transfer_auditor_encryption_keypair,
ct_mint_withdraw_withheld_authority_encryption_keypair, ct_mint_withdraw_withheld_authority_encryption_keypair,
.. ..
} = ConfidentialTransferMintWithKeypairs::new(); } = ConfidentialTransferMintWithKeypairs::new();
@ -1359,11 +1382,12 @@ async fn ct_withdraw_withheld_tokens_from_mint() {
maximum_fee: TEST_MAXIMUM_FEE, maximum_fee: TEST_MAXIMUM_FEE,
}, },
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -1434,11 +1458,8 @@ async fn ct_withdraw_withheld_tokens_from_mint() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
&ct_mint &ct_mint_withdraw_withheld_authority_encryption_keypair.public,
.withdraw_withheld_authority_encryption_pubkey
.try_into()
.unwrap(),
&epoch_info, &epoch_info,
) )
.await .await
@ -1521,11 +1542,12 @@ async fn ct_withdraw_withheld_tokens_from_accounts() {
maximum_fee: TEST_MAXIMUM_FEE, maximum_fee: TEST_MAXIMUM_FEE,
}, },
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -1565,7 +1587,7 @@ async fn ct_withdraw_withheld_tokens_from_accounts() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint_transfer_auditor_encryption_keypair.public, Some(ct_mint_transfer_auditor_encryption_keypair.public),
&ct_mint_withdraw_withheld_authority_encryption_keypair.public, &ct_mint_withdraw_withheld_authority_encryption_keypair.public,
&epoch_info, &epoch_info,
) )
@ -1628,17 +1650,21 @@ async fn ct_withdraw_withheld_tokens_from_accounts() {
#[cfg(feature = "zk-ops")] #[cfg(feature = "zk-ops")]
#[tokio::test] #[tokio::test]
async fn ct_transfer_memo() { async fn ct_transfer_memo() {
let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = let ConfidentialTransferMintWithKeypairs {
ConfidentialTransferMintWithKeypairs::new(); ct_mint,
ct_mint_transfer_auditor_encryption_keypair,
..
} = ConfidentialTransferMintWithKeypairs::new();
let mut context = TestContext::new().await; let mut context = TestContext::new().await;
context context
.init_token_with_mint(vec![ .init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -1676,7 +1702,7 @@ async fn ct_transfer_memo() {
42, 42,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap_err(); .unwrap_err();
@ -1702,7 +1728,7 @@ async fn ct_transfer_memo() {
42, 42,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
) )
.await .await
.unwrap(); .unwrap();
@ -1735,8 +1761,12 @@ async fn ct_transfer_memo() {
#[cfg(feature = "zk-ops")] #[cfg(feature = "zk-ops")]
#[tokio::test] #[tokio::test]
async fn ct_transfer_with_fee_memo() { async fn ct_transfer_with_fee_memo() {
let ConfidentialTransferMintWithKeypairs { ct_mint, .. } = let ConfidentialTransferMintWithKeypairs {
ConfidentialTransferMintWithKeypairs::new(); ct_mint,
ct_mint_transfer_auditor_encryption_keypair,
ct_mint_withdraw_withheld_authority_encryption_keypair,
..
} = ConfidentialTransferMintWithKeypairs::new();
let mut context = TestContext::new().await; let mut context = TestContext::new().await;
context context
@ -1748,11 +1778,12 @@ async fn ct_transfer_with_fee_memo() {
maximum_fee: TEST_MAXIMUM_FEE, maximum_fee: TEST_MAXIMUM_FEE,
}, },
ExtensionInitializationParams::ConfidentialTransferMint { ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(ct_mint.authority), authority: ct_mint.authority.into(),
auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(), auto_approve_new_accounts: ct_mint.auto_approve_new_accounts.try_into().unwrap(),
auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey, auditor_encryption_pubkey: ct_mint.auditor_encryption_pubkey.into(),
withdraw_withheld_authority_encryption_pubkey: ct_mint withdraw_withheld_authority_encryption_pubkey: ct_mint
.withdraw_withheld_authority_encryption_pubkey, .withdraw_withheld_authority_encryption_pubkey
.into(),
}, },
]) ])
.await .await
@ -1792,11 +1823,8 @@ async fn ct_transfer_with_fee_memo() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
&ct_mint &ct_mint_withdraw_withheld_authority_encryption_keypair.public,
.withdraw_withheld_authority_encryption_pubkey
.try_into()
.unwrap(),
&epoch_info, &epoch_info,
) )
.await .await
@ -1822,11 +1850,8 @@ async fn ct_transfer_with_fee_memo() {
100, 100,
&extension.available_balance.try_into().unwrap(), &extension.available_balance.try_into().unwrap(),
&bob_meta.elgamal_keypair.public, &bob_meta.elgamal_keypair.public,
&ct_mint.auditor_encryption_pubkey.try_into().unwrap(), Some(ct_mint_transfer_auditor_encryption_keypair.public),
&ct_mint &ct_mint_withdraw_withheld_authority_encryption_keypair.public,
.withdraw_withheld_authority_encryption_pubkey
.try_into()
.unwrap(),
&epoch_info, &epoch_info,
) )
.await .await

View File

@ -431,14 +431,14 @@ pub enum ConfidentialTransferInstruction {
pub struct InitializeMintData { pub struct InitializeMintData {
/// Authority to modify the `ConfidentialTransferMint` configuration and to approve new /// Authority to modify the `ConfidentialTransferMint` configuration and to approve new
/// accounts. /// accounts.
pub authority: Pubkey, pub authority: OptionalNonZeroPubkey,
/// Determines if newly configured accounts must be approved by the `authority` before they may /// Determines if newly configured accounts must be approved by the `authority` before they may
/// be used by the user. /// be used by the user.
pub auto_approve_new_accounts: PodBool, pub auto_approve_new_accounts: PodBool,
/// New authority to decode any transfer amount in a confidential transfer. /// New authority to decode any transfer amount in a confidential transfer.
pub auditor_encryption_pubkey: EncryptionPubkey, pub auditor_encryption_pubkey: OptionalNonZeroEncryptionPubkey,
/// Authority to withdraw withheld fees that are associated with accounts. /// Authority to withdraw withheld fees that are associated with accounts.
pub withdraw_withheld_authority_encryption_pubkey: EncryptionPubkey, pub withdraw_withheld_authority_encryption_pubkey: OptionalNonZeroEncryptionPubkey,
} }
/// Data expected by `ConfidentialTransferInstruction::UpdateMint` /// Data expected by `ConfidentialTransferInstruction::UpdateMint`
@ -449,7 +449,7 @@ pub struct UpdateMintData {
/// be used by the user. /// be used by the user.
pub auto_approve_new_accounts: PodBool, pub auto_approve_new_accounts: PodBool,
/// New authority to decode any transfer amount in a confidential transfer. /// New authority to decode any transfer amount in a confidential transfer.
pub auditor_encryption_pubkey: EncryptionPubkey, pub auditor_encryption_pubkey: OptionalNonZeroEncryptionPubkey,
} }
/// Data expected by `ConfidentialTransferInstruction::ConfigureAccount` /// Data expected by `ConfidentialTransferInstruction::ConfigureAccount`
@ -547,32 +547,25 @@ pub struct WithdrawWithheldTokensFromAccountsData {
pub fn initialize_mint( pub fn initialize_mint(
token_program_id: &Pubkey, token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
authority: Option<&Pubkey>, authority: Option<Pubkey>,
auto_approve_new_accounts: bool, auto_approve_new_accounts: bool,
auditor_encryption_pubkey: &EncryptionPubkey, auditor_encryption_pubkey: Option<EncryptionPubkey>,
withdraw_withheld_authority_encryption_pubkey: &EncryptionPubkey, withdraw_withheld_authority_encryption_pubkey: Option<EncryptionPubkey>,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?; check_program_account(token_program_id)?;
let accounts = vec![AccountMeta::new(*mint, false)]; let accounts = vec![AccountMeta::new(*mint, false)];
// TODO: use `OptionalNonZeroPubkey`
let authority = if let Some(authority) = authority {
*authority
} else {
Pubkey::default()
};
Ok(encode_instruction( Ok(encode_instruction(
token_program_id, token_program_id,
accounts, accounts,
TokenInstruction::ConfidentialTransferExtension, TokenInstruction::ConfidentialTransferExtension,
ConfidentialTransferInstruction::InitializeMint, ConfidentialTransferInstruction::InitializeMint,
&InitializeMintData { &InitializeMintData {
authority, authority: authority.try_into()?,
auto_approve_new_accounts: auto_approve_new_accounts.into(), auto_approve_new_accounts: auto_approve_new_accounts.into(),
auditor_encryption_pubkey: *auditor_encryption_pubkey, auditor_encryption_pubkey: auditor_encryption_pubkey.try_into()?,
withdraw_withheld_authority_encryption_pubkey: withdraw_withheld_authority_encryption_pubkey:
*withdraw_withheld_authority_encryption_pubkey, withdraw_withheld_authority_encryption_pubkey.try_into()?,
}, },
)) ))
} }
@ -585,7 +578,7 @@ pub fn update_mint(
authority: &Pubkey, authority: &Pubkey,
new_authority: Option<&Pubkey>, new_authority: Option<&Pubkey>,
auto_approve_new_accounts: bool, auto_approve_new_accounts: bool,
auditor_encryption_pubkey: &EncryptionPubkey, auditor_encryption_pubkey: Option<EncryptionPubkey>,
) -> Result<Instruction, ProgramError> { ) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?; check_program_account(token_program_id)?;
@ -606,7 +599,7 @@ pub fn update_mint(
ConfidentialTransferInstruction::UpdateMint, ConfidentialTransferInstruction::UpdateMint,
&UpdateMintData { &UpdateMintData {
auto_approve_new_accounts: auto_approve_new_accounts.into(), auto_approve_new_accounts: auto_approve_new_accounts.into(),
auditor_encryption_pubkey: *auditor_encryption_pubkey, auditor_encryption_pubkey: auditor_encryption_pubkey.try_into()?,
}, },
)) ))
} }

View File

@ -5,7 +5,7 @@ use {
pod::*, pod::*,
}, },
bytemuck::{Pod, Zeroable}, bytemuck::{Pod, Zeroable},
solana_program::{entrypoint::ProgramResult, pubkey::Pubkey}, solana_program::entrypoint::ProgramResult,
solana_zk_token_sdk::zk_token_elgamal::pod, solana_zk_token_sdk::zk_token_elgamal::pod,
}; };
@ -25,8 +25,6 @@ pub mod instruction;
/// Confidential Transfer Extension processor /// Confidential Transfer Extension processor
pub mod processor; pub mod processor;
/// ElGamal public key used for encryption
pub type EncryptionPubkey = pod::ElGamalPubkey;
/// ElGamal ciphertext containing an account balance /// ElGamal ciphertext containing an account balance
pub type EncryptedBalance = pod::ElGamalCiphertext; pub type EncryptedBalance = pod::ElGamalCiphertext;
/// Authenticated encryption containing an account balance /// Authenticated encryption containing an account balance
@ -43,11 +41,8 @@ pub struct ConfidentialTransferMint {
/// Authority to modify the `ConfidentialTransferMint` configuration and to approve new /// Authority to modify the `ConfidentialTransferMint` configuration and to approve new
/// accounts (if `auto_approve_new_accounts` is true) /// accounts (if `auto_approve_new_accounts` is true)
/// ///
/// Note that setting an authority of `Pubkey::default()` is the idiomatic way to disable
/// future changes to the configuration.
///
/// The legacy Token Multisig account is not supported as the authority /// The legacy Token Multisig account is not supported as the authority
pub authority: Pubkey, pub authority: OptionalNonZeroPubkey,
/// Indicate if newly configured accounts must be approved by the `authority` before they may be /// Indicate if newly configured accounts must be approved by the `authority` before they may be
/// used by the user. /// used by the user.
@ -58,25 +53,21 @@ pub struct ConfidentialTransferMint {
pub auto_approve_new_accounts: PodBool, pub auto_approve_new_accounts: PodBool,
/// Authority to decode any transfer amount in a confidential transafer. /// Authority to decode any transfer amount in a confidential transafer.
/// pub auditor_encryption_pubkey: OptionalNonZeroEncryptionPubkey,
/// * If non-zero, transfers must include ElGamal cyphertext with this public key permitting the
/// auditor to decode the transfer amount.
/// * If all zero, auditing is currently disabled.
pub auditor_encryption_pubkey: EncryptionPubkey,
/// Authority to withraw withheld fees that are associated with accounts. It must be set to an /// Authority to withraw withheld fees that are associated with accounts. It must be set to
/// all zero pubkey if the mint is not extended for fees. /// `None` if the mint is not extended for fees.
/// ///
/// Note that the withdraw withheld authority has the ability to decode any withheld fee /// Note that the withdraw withheld authority has the ability to decode any withheld fee
/// amount that are associated with accounts. When combined with the fee parameters, the /// amount that are associated with accounts. When combined with the fee parameters, the
/// withheld fee amounts can reveal information about transfer amounts. /// withheld fee amounts can reveal information about transfer amounts.
/// ///
/// * If non-zero, transfers must include ElGamal cyphertext of the transfer fee with this /// * If not `None`, transfers must include ElGamal cyphertext of the transfer fee with this
/// public key. If this is the case, but the base mint is not extended for fees, then any /// public key. If this is the case, but the base mint is not extended for fees, then any
/// transfer will fail. /// transfer will fail.
/// * If all zero, transfer fee is disabled. If this is the case, but the base mint is extended /// * If `None`, transfer fee is disabled. If this is the case, but the base mint is extended
/// for fees, then any transfer will fail. /// for fees, then any transfer will fail.
pub withdraw_withheld_authority_encryption_pubkey: EncryptionPubkey, pub withdraw_withheld_authority_encryption_pubkey: OptionalNonZeroEncryptionPubkey,
/// Withheld transfer fee confidential tokens that have been moved to the mint for withdrawal. /// Withheld transfer fee confidential tokens that have been moved to the mint for withdrawal.
/// This will always be zero if fees are never enabled. /// This will always be zero if fees are never enabled.

View File

@ -55,10 +55,10 @@ fn decode_proof_instruction<T: Pod>(
/// Processes an [InitializeMint] instruction. /// Processes an [InitializeMint] instruction.
fn process_initialize_mint( fn process_initialize_mint(
accounts: &[AccountInfo], accounts: &[AccountInfo],
authority: &Pubkey, authority: &OptionalNonZeroPubkey,
auto_approve_new_account: PodBool, auto_approve_new_account: PodBool,
auditor_encryption_pubkey: &EncryptionPubkey, auditor_encryption_pubkey: &OptionalNonZeroEncryptionPubkey,
withdraw_withheld_authority_encryption_pubkey: &EncryptionPubkey, withdraw_withheld_authority_encryption_pubkey: &OptionalNonZeroEncryptionPubkey,
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
let mint_info = next_account_info(account_info_iter)?; let mint_info = next_account_info(account_info_iter)?;
@ -82,7 +82,7 @@ fn process_initialize_mint(
fn process_update_mint( fn process_update_mint(
accounts: &[AccountInfo], accounts: &[AccountInfo],
auto_approve_new_account: PodBool, auto_approve_new_account: PodBool,
auditor_encryption_pubkey: &EncryptionPubkey, auditor_encryption_pubkey: &OptionalNonZeroEncryptionPubkey,
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
let mint_info = next_account_info(account_info_iter)?; let mint_info = next_account_info(account_info_iter)?;
@ -93,18 +93,26 @@ fn process_update_mint(
let mint_data = &mut mint_info.data.borrow_mut(); let mint_data = &mut mint_info.data.borrow_mut();
let mut mint = StateWithExtensionsMut::<Mint>::unpack(mint_data)?; let mut mint = StateWithExtensionsMut::<Mint>::unpack(mint_data)?;
let confidential_transfer_mint = mint.get_extension_mut::<ConfidentialTransferMint>()?; let confidential_transfer_mint = mint.get_extension_mut::<ConfidentialTransferMint>()?;
let maybe_confidential_transfer_mint_authority: Option<Pubkey> =
confidential_transfer_mint.authority.into();
let confidential_transfer_mint_authority =
maybe_confidential_transfer_mint_authority.ok_or(TokenError::NoAuthorityExists)?;
if authority_info.is_signer if !authority_info.is_signer
&& confidential_transfer_mint.authority == *authority_info.key || confidential_transfer_mint_authority != *authority_info.key
&& (new_authority_info.is_signer || *new_authority_info.key == Pubkey::default()) || (!new_authority_info.is_signer && *new_authority_info.key != Pubkey::default())
{ {
confidential_transfer_mint.authority = *new_authority_info.key; return Err(ProgramError::MissingRequiredSignature);
confidential_transfer_mint.auto_approve_new_accounts = auto_approve_new_account;
confidential_transfer_mint.auditor_encryption_pubkey = *auditor_encryption_pubkey;
Ok(())
} else {
Err(ProgramError::MissingRequiredSignature)
} }
if *new_authority_info.key == Pubkey::default() {
confidential_transfer_mint.authority = None.try_into()?;
} else {
confidential_transfer_mint.authority = Some(*new_authority_info.key).try_into()?;
}
confidential_transfer_mint.auto_approve_new_accounts = auto_approve_new_account;
confidential_transfer_mint.auditor_encryption_pubkey = *auditor_encryption_pubkey;
Ok(())
} }
/// Processes a [ConfigureAccount] instruction. /// Processes a [ConfigureAccount] instruction.
@ -191,8 +199,12 @@ fn process_approve_account(accounts: &[AccountInfo]) -> ProgramResult {
let mint_data = &mint_info.data.borrow_mut(); let mint_data = &mint_info.data.borrow_mut();
let mint = StateWithExtensions::<Mint>::unpack(mint_data)?; let mint = StateWithExtensions::<Mint>::unpack(mint_data)?;
let confidential_transfer_mint = mint.get_extension::<ConfidentialTransferMint>()?; let confidential_transfer_mint = mint.get_extension::<ConfidentialTransferMint>()?;
let maybe_confidential_transfer_mint_authority: Option<Pubkey> =
confidential_transfer_mint.authority.into();
let confidential_transfer_mint_authority =
maybe_confidential_transfer_mint_authority.ok_or(TokenError::NoAuthorityExists)?;
if authority_info.is_signer && *authority_info.key == confidential_transfer_mint.authority { if authority_info.is_signer && *authority_info.key == confidential_transfer_mint_authority {
let mut confidential_transfer_state = let mut confidential_transfer_state =
token_account.get_extension_mut::<ConfidentialTransferAccount>()?; token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
confidential_transfer_state.approved = true.into(); confidential_transfer_state.approved = true.into();
@ -502,8 +514,9 @@ fn process_transfer(
)?; )?;
// Check that the auditor encryption public key associated wth the confidential mint is // Check that the auditor encryption public key associated wth the confidential mint is
// consistent with what was actually used to generate the zkp. // consistent with what was actually used to generate the zkp.
if proof_data.transfer_pubkeys.auditor_pubkey if !confidential_transfer_mint
!= confidential_transfer_mint.auditor_encryption_pubkey .auditor_encryption_pubkey
.equals(&proof_data.transfer_pubkeys.auditor_pubkey)
{ {
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
} }
@ -562,15 +575,19 @@ fn process_transfer(
)?; )?;
// Check that the encryption public keys associated with the confidential extension mint // Check that the encryption public keys associated with the confidential extension mint
// are consistent with the keys that were used to generate the zkp. // are consistent with the keys that were used to generate the zkp.
if proof_data.transfer_with_fee_pubkeys.auditor_pubkey if !confidential_transfer_mint
!= confidential_transfer_mint.auditor_encryption_pubkey .auditor_encryption_pubkey
.equals(&proof_data.transfer_with_fee_pubkeys.auditor_pubkey)
{ {
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
} }
if proof_data if !confidential_transfer_mint
.transfer_with_fee_pubkeys .withdraw_withheld_authority_encryption_pubkey
.withdraw_withheld_authority_pubkey .equals(
!= confidential_transfer_mint.withdraw_withheld_authority_encryption_pubkey &proof_data
.transfer_with_fee_pubkeys
.withdraw_withheld_authority_pubkey,
)
{ {
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
} }
@ -970,8 +987,9 @@ fn process_withdraw_withheld_tokens_from_mint(
)?; )?;
// Checks that the withdraw authority encryption public key associated with the mint is // Checks that the withdraw authority encryption public key associated with the mint is
// consistent with what was actually used to generate the zkp. // consistent with what was actually used to generate the zkp.
if proof_data.withdraw_withheld_authority_pubkey if !confidential_transfer_mint
!= confidential_transfer_mint.withdraw_withheld_authority_encryption_pubkey .withdraw_withheld_authority_encryption_pubkey
.equals(&proof_data.withdraw_withheld_authority_pubkey)
{ {
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
} }
@ -1097,8 +1115,9 @@ fn process_withdraw_withheld_tokens_from_accounts(
// Checks that the withdraw authority encryption public key associated with the mint is // Checks that the withdraw authority encryption public key associated with the mint is
// consistent with what was actually used to generate the zkp. // consistent with what was actually used to generate the zkp.
let confidential_transfer_mint = mint.get_extension_mut::<ConfidentialTransferMint>()?; let confidential_transfer_mint = mint.get_extension_mut::<ConfidentialTransferMint>()?;
if proof_data.withdraw_withheld_authority_pubkey if !confidential_transfer_mint
!= confidential_transfer_mint.withdraw_withheld_authority_encryption_pubkey .withdraw_withheld_authority_encryption_pubkey
.equals(&proof_data.withdraw_withheld_authority_pubkey)
{ {
return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into());
} }

View File

@ -2,6 +2,7 @@
use { use {
bytemuck::{Pod, Zeroable}, bytemuck::{Pod, Zeroable},
solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey}, solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey},
solana_zk_token_sdk::zk_token_elgamal::pod,
std::convert::TryFrom, std::convert::TryFrom,
}; };
@ -59,6 +60,44 @@ impl From<OptionalNonZeroPubkey> for COption<Pubkey> {
} }
} }
/// ElGamal public key used for encryption
pub type EncryptionPubkey = pod::ElGamalPubkey;
/// An EncryptionPubkey that encodes `None` as all `0`, meant to be usable as a Pod type.
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
#[repr(transparent)]
pub struct OptionalNonZeroEncryptionPubkey(EncryptionPubkey);
impl OptionalNonZeroEncryptionPubkey {
/// Checks equality between an OptionalNonZeroEncryptionPubkey and an EncryptionPubkey when
/// interpreted as bytes.
pub fn equals(&self, other: &EncryptionPubkey) -> bool {
&self.0 == other
}
}
impl TryFrom<Option<EncryptionPubkey>> for OptionalNonZeroEncryptionPubkey {
type Error = ProgramError;
fn try_from(p: Option<EncryptionPubkey>) -> Result<Self, Self::Error> {
match p {
None => Ok(Self(EncryptionPubkey::default())),
Some(encryption_pubkey) => {
if encryption_pubkey == EncryptionPubkey::default() {
Err(ProgramError::InvalidArgument)
} else {
Ok(Self(encryption_pubkey))
}
}
}
}
}
impl From<OptionalNonZeroEncryptionPubkey> for Option<EncryptionPubkey> {
fn from(p: OptionalNonZeroEncryptionPubkey) -> Self {
if p.0 == EncryptionPubkey::default() {
None
} else {
Some(p.0)
}
}
}
/// The standard `bool` is not a `Pod`, define a replacement that is /// The standard `bool` is not a `Pod`, define a replacement that is
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
#[repr(transparent)] #[repr(transparent)]