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

[program-2022] Add auditor ciphertexts to instruction data #7480

Merged
merged 12 commits into from
Nov 15, 2024
22 changes: 18 additions & 4 deletions token/cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ use {
},
spl_token_client::{
client::{ProgramRpcClientSendTransaction, RpcClientResponse},
token::{ComputeUnitLimit, ExtensionInitializationParams, ProofAccount, Token},
token::{
ComputeUnitLimit, ExtensionInitializationParams, ProofAccount,
ProofAccountWithCiphertext, Token,
},
},
spl_token_confidential_transfer_proof_generation::{
transfer::TransferProofData, withdraw::WithdrawProofData,
Expand Down Expand Up @@ -1611,7 +1614,7 @@ async fn command_transfer(

let TransferProofData {
equality_proof_data,
ciphertext_validity_proof_data,
ciphertext_validity_proof_data_with_ciphertext,
range_proof_data,
} = transfer_account_info
.generate_split_transfer_proof_data(
Expand All @@ -1623,6 +1626,11 @@ async fn command_transfer(
)
.unwrap();

let transfer_amount_auditor_ciphertext_lo =
ciphertext_validity_proof_data_with_ciphertext.ciphertext_lo;
let transfer_amount_auditor_ciphertext_hi =
ciphertext_validity_proof_data_with_ciphertext.ciphertext_hi;

// setup proofs
let create_range_proof_context_signer = &[&range_proof_context_state_account];
let create_equality_proof_context_signer = &[&equality_proof_context_state_account];
Expand All @@ -1647,7 +1655,7 @@ async fn command_transfer(
token.confidential_transfer_create_context_state_account(
&ciphertext_validity_proof_pubkey,
&context_state_authority_pubkey,
&ciphertext_validity_proof_data,
&ciphertext_validity_proof_data_with_ciphertext.proof_data,
false,
create_ciphertext_validity_proof_context_signer
)
Expand All @@ -1661,13 +1669,19 @@ async fn command_transfer(
let range_proof_context_proof_account =
ProofAccount::ContextAccount(range_proof_pubkey);

let ciphertext_validity_proof_account_with_ciphertext = ProofAccountWithCiphertext {
proof_account: ciphertext_validity_proof_context_proof_account,
ciphertext_lo: transfer_amount_auditor_ciphertext_lo,
ciphertext_hi: transfer_amount_auditor_ciphertext_hi,
};

let transfer_result = token
.confidential_transfer_transfer(
&sender,
&recipient_token_account,
&sender_owner,
Some(&equality_proof_context_proof_account),
Some(&ciphertext_validity_proof_context_proof_account),
Some(&ciphertext_validity_proof_account_with_ciphertext),
Some(&range_proof_context_proof_account),
transfer_balance,
Some(transfer_account_info),
Expand Down
171 changes: 113 additions & 58 deletions token/client/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use {
encryption::{
auth_encryption::AeKey,
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey},
pod::elgamal::PodElGamalPubkey,
pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
},
zk_elgamal_proof_program::{
self,
Expand Down Expand Up @@ -348,6 +348,12 @@ pub enum ProofAccount {
RecordAccount(Pubkey, u32),
}

pub struct ProofAccountWithCiphertext {
pub proof_account: ProofAccount,
pub ciphertext_lo: PodElGamalCiphertext,
pub ciphertext_hi: PodElGamalCiphertext,
}

pub struct Token<T> {
client: Arc<dyn ProgramClient<T>>,
pubkey: Pubkey, /* token mint */
Expand Down Expand Up @@ -2198,7 +2204,7 @@ where
destination_account: &Pubkey,
source_authority: &Pubkey,
equality_proof_account: Option<&ProofAccount>,
ciphertext_validity_proof_account: Option<&ProofAccount>,
ciphertext_validity_proof_account_with_ciphertext: Option<&ProofAccountWithCiphertext>,
range_proof_account: Option<&ProofAccount>,
transfer_amount: u64,
account_info: Option<TransferAccountInfo>,
Expand All @@ -2220,46 +2226,65 @@ where
TransferAccountInfo::new(confidential_transfer_account)
};

let (equality_proof_data, ciphertext_validity_proof_data, range_proof_data) = if [
equality_proof_account,
ciphertext_validity_proof_account,
range_proof_account,
]
.iter()
.all(|proof_account| proof_account.is_some())
{
(None, None, None)
} else {
let TransferProofData {
equality_proof_data,
ciphertext_validity_proof_data,
range_proof_data,
} = account_info
.generate_split_transfer_proof_data(
transfer_amount,
source_elgamal_keypair,
source_aes_key,
destination_elgamal_pubkey,
auditor_elgamal_pubkey,
)
.map_err(|_| TokenError::ProofGeneration)?;
let (equality_proof_data, ciphertext_validity_proof_data_with_ciphertext, range_proof_data) =
if equality_proof_account.is_some()
&& ciphertext_validity_proof_account_with_ciphertext.is_some()
&& range_proof_account.is_some()
{
(None, None, None)
} else {
let TransferProofData {
equality_proof_data,
ciphertext_validity_proof_data_with_ciphertext,
range_proof_data,
} = account_info
.generate_split_transfer_proof_data(
transfer_amount,
source_elgamal_keypair,
source_aes_key,
destination_elgamal_pubkey,
auditor_elgamal_pubkey,
)
.map_err(|_| TokenError::ProofGeneration)?;

// if proof accounts are none, then proof data must be included as instruction
// data
let equality_proof_data = equality_proof_account
.is_none()
.then_some(equality_proof_data);
let ciphertext_validity_proof_data = ciphertext_validity_proof_account
.is_none()
.then_some(ciphertext_validity_proof_data);
let range_proof_data = range_proof_account.is_none().then_some(range_proof_data);
// if proof accounts are none, then proof data must be included as instruction
// data
let equality_proof_data = equality_proof_account
.is_none()
.then_some(equality_proof_data);
let ciphertext_validity_proof_data_with_ciphertext =
ciphertext_validity_proof_account_with_ciphertext
.is_none()
.then_some(ciphertext_validity_proof_data_with_ciphertext);
let range_proof_data = range_proof_account.is_none().then_some(range_proof_data);

(
equality_proof_data,
ciphertext_validity_proof_data,
range_proof_data,
)
};
(
equality_proof_data,
ciphertext_validity_proof_data_with_ciphertext,
range_proof_data,
)
};

let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) =
if let Some(proof_data_with_ciphertext) = ciphertext_validity_proof_data_with_ciphertext
{
(
proof_data_with_ciphertext.ciphertext_lo,
proof_data_with_ciphertext.ciphertext_hi,
)
} else {
// unwrap is safe as long as either `proof_data_with_ciphertext`,
// `proof_account_with_ciphertext` is `Some(..)`, which is guaranteed by the
// previous check
(
ciphertext_validity_proof_account_with_ciphertext
.unwrap()
.ciphertext_lo,
ciphertext_validity_proof_account_with_ciphertext
.unwrap()
.ciphertext_hi,
)
};

// cannot panic as long as either `proof_data` or `proof_account` is `Some(..)`,
// which is guaranteed by the previous check
Expand All @@ -2269,9 +2294,11 @@ where
1,
)
.unwrap();
let ciphertext_validity_proof_data =
ciphertext_validity_proof_data_with_ciphertext.map(|data| data.proof_data);
let ciphertext_validity_proof_location = Self::confidential_transfer_create_proof_location(
ciphertext_validity_proof_data.as_ref(),
ciphertext_validity_proof_account,
ciphertext_validity_proof_account_with_ciphertext.map(|account| &account.proof_account),
2,
)
.unwrap();
Expand All @@ -2292,6 +2319,8 @@ where
self.get_address(),
destination_account,
new_decryptable_available_balance.into(),
&transfer_amount_auditor_ciphertext_lo,
&transfer_amount_auditor_ciphertext_hi,
source_authority,
&multisig_signers,
equality_proof_location,
Expand Down Expand Up @@ -2526,7 +2555,9 @@ where
destination_account: &Pubkey,
source_authority: &Pubkey,
equality_proof_account: Option<&ProofAccount>,
transfer_amount_ciphertext_validity_proof_account: Option<&ProofAccount>,
transfer_amount_ciphertext_validity_proof_account_with_ciphertext: Option<
&ProofAccountWithCiphertext,
>,
percentage_with_cap_proof_account: Option<&ProofAccount>,
fee_ciphertext_validity_proof_account: Option<&ProofAccount>,
range_proof_account: Option<&ProofAccount>,
Expand Down Expand Up @@ -2555,26 +2586,22 @@ where

let (
equality_proof_data,
transfer_amount_ciphertext_validity_proof_data,
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
percentage_with_cap_proof_data,
fee_ciphertext_validity_proof_data,
range_proof_data,
) = if [
equality_proof_account,
transfer_amount_ciphertext_validity_proof_account,
percentage_with_cap_proof_account,
fee_ciphertext_validity_proof_account,
range_proof_account,
]
.iter()
.all(|proof_account| proof_account.is_some())
) = if equality_proof_account.is_some()
&& transfer_amount_ciphertext_validity_proof_account_with_ciphertext.is_some()
&& percentage_with_cap_proof_account.is_some()
&& fee_ciphertext_validity_proof_account.is_some()
&& range_proof_account.is_some()
{
// is all proofs come from accounts, then skip proof generation
(None, None, None, None, None)
} else {
let TransferWithFeeProofData {
equality_proof_data,
transfer_amount_ciphertext_validity_proof_data,
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
percentage_with_cap_proof_data,
fee_ciphertext_validity_proof_data,
range_proof_data,
Expand All @@ -2594,10 +2621,10 @@ where
let equality_proof_data = equality_proof_account
.is_none()
.then_some(equality_proof_data);
let transfer_amount_ciphertext_validity_proof_data =
transfer_amount_ciphertext_validity_proof_account
let transfer_amount_ciphertext_validity_proof_data_with_ciphertext =
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
.is_none()
.then_some(transfer_amount_ciphertext_validity_proof_data);
.then_some(transfer_amount_ciphertext_validity_proof_data_with_ciphertext);
let percentage_with_cap_proof_data = percentage_with_cap_proof_account
.is_none()
.then_some(percentage_with_cap_proof_data);
Expand All @@ -2608,13 +2635,35 @@ where

(
equality_proof_data,
transfer_amount_ciphertext_validity_proof_data,
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
percentage_with_cap_proof_data,
fee_ciphertext_validity_proof_data,
range_proof_data,
)
};

let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) =
if let Some(proof_data_with_ciphertext) =
transfer_amount_ciphertext_validity_proof_data_with_ciphertext
{
(
proof_data_with_ciphertext.ciphertext_lo,
proof_data_with_ciphertext.ciphertext_hi,
)
} else {
// unwrap is safe as long as either `proof_data_with_ciphertext`,
// `proof_account_with_ciphertext` is `Some(..)`, which is guaranteed by the
// previous check
(
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
.unwrap()
.ciphertext_lo,
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
.unwrap()
.ciphertext_hi,
)
};

// cannot panic as long as either `proof_data` or `proof_account` is `Some(..)`,
// which is guaranteed by the previous check
let equality_proof_location = Self::confidential_transfer_create_proof_location(
Expand All @@ -2623,10 +2672,14 @@ where
1,
)
.unwrap();
let transfer_amount_ciphertext_validity_proof_data =
transfer_amount_ciphertext_validity_proof_data_with_ciphertext
.map(|data| data.proof_data);
let transfer_amount_ciphertext_validity_proof_location =
Self::confidential_transfer_create_proof_location(
transfer_amount_ciphertext_validity_proof_data.as_ref(),
transfer_amount_ciphertext_validity_proof_account,
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
.map(|account| &account.proof_account),
2,
)
.unwrap();
Expand Down Expand Up @@ -2660,6 +2713,8 @@ where
self.get_address(),
destination_account,
new_decryptable_available_balance.into(),
&transfer_amount_auditor_ciphertext_lo,
&transfer_amount_auditor_ciphertext_hi,
source_authority,
&multisig_signers,
equality_proof_location,
Expand Down
Loading
Loading