Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 45b214f

Browse files
[program-2022] Add auditor ciphertexts to instruction data (#7480)
* add auditor ciphertext to transfer instruction data * add auditor ciphertext to confidential mint and burn instruction data * cargo fmt * cargo clippy * import `elgamalciphertext_fromstr` * update token-cli * use `map_err(TokenError::from)` * add `CiphertextValidityProofWithCiphertext` type * update token-cli using the updated syntax * add comments describing the type `CiphertextValidityProofWithCiphertext` * update proof tests * update to `CiphertextValidityProofWithAuditorCiphertext`
1 parent 115e594 commit 45b214f

File tree

17 files changed

+558
-134
lines changed

17 files changed

+558
-134
lines changed

token/cli/src/command.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ use {
6666
},
6767
spl_token_client::{
6868
client::{ProgramRpcClientSendTransaction, RpcClientResponse},
69-
token::{ComputeUnitLimit, ExtensionInitializationParams, ProofAccount, Token},
69+
token::{
70+
ComputeUnitLimit, ExtensionInitializationParams, ProofAccount,
71+
ProofAccountWithCiphertext, Token,
72+
},
7073
},
7174
spl_token_confidential_transfer_proof_generation::{
7275
transfer::TransferProofData, withdraw::WithdrawProofData,
@@ -1611,7 +1614,7 @@ async fn command_transfer(
16111614

16121615
let TransferProofData {
16131616
equality_proof_data,
1614-
ciphertext_validity_proof_data,
1617+
ciphertext_validity_proof_data_with_ciphertext,
16151618
range_proof_data,
16161619
} = transfer_account_info
16171620
.generate_split_transfer_proof_data(
@@ -1623,6 +1626,11 @@ async fn command_transfer(
16231626
)
16241627
.unwrap();
16251628

1629+
let transfer_amount_auditor_ciphertext_lo =
1630+
ciphertext_validity_proof_data_with_ciphertext.ciphertext_lo;
1631+
let transfer_amount_auditor_ciphertext_hi =
1632+
ciphertext_validity_proof_data_with_ciphertext.ciphertext_hi;
1633+
16261634
// setup proofs
16271635
let create_range_proof_context_signer = &[&range_proof_context_state_account];
16281636
let create_equality_proof_context_signer = &[&equality_proof_context_state_account];
@@ -1647,7 +1655,7 @@ async fn command_transfer(
16471655
token.confidential_transfer_create_context_state_account(
16481656
&ciphertext_validity_proof_pubkey,
16491657
&context_state_authority_pubkey,
1650-
&ciphertext_validity_proof_data,
1658+
&ciphertext_validity_proof_data_with_ciphertext.proof_data,
16511659
false,
16521660
create_ciphertext_validity_proof_context_signer
16531661
)
@@ -1661,13 +1669,19 @@ async fn command_transfer(
16611669
let range_proof_context_proof_account =
16621670
ProofAccount::ContextAccount(range_proof_pubkey);
16631671

1672+
let ciphertext_validity_proof_account_with_ciphertext = ProofAccountWithCiphertext {
1673+
proof_account: ciphertext_validity_proof_context_proof_account,
1674+
ciphertext_lo: transfer_amount_auditor_ciphertext_lo,
1675+
ciphertext_hi: transfer_amount_auditor_ciphertext_hi,
1676+
};
1677+
16641678
let transfer_result = token
16651679
.confidential_transfer_transfer(
16661680
&sender,
16671681
&recipient_token_account,
16681682
&sender_owner,
16691683
Some(&equality_proof_context_proof_account),
1670-
Some(&ciphertext_validity_proof_context_proof_account),
1684+
Some(&ciphertext_validity_proof_account_with_ciphertext),
16711685
Some(&range_proof_context_proof_account),
16721686
transfer_balance,
16731687
Some(transfer_account_info),

token/client/src/token.rs

+113-58
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use {
5151
encryption::{
5252
auth_encryption::AeKey,
5353
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey},
54-
pod::elgamal::PodElGamalPubkey,
54+
pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
5555
},
5656
zk_elgamal_proof_program::{
5757
self,
@@ -348,6 +348,12 @@ pub enum ProofAccount {
348348
RecordAccount(Pubkey, u32),
349349
}
350350

351+
pub struct ProofAccountWithCiphertext {
352+
pub proof_account: ProofAccount,
353+
pub ciphertext_lo: PodElGamalCiphertext,
354+
pub ciphertext_hi: PodElGamalCiphertext,
355+
}
356+
351357
pub struct Token<T> {
352358
client: Arc<dyn ProgramClient<T>>,
353359
pubkey: Pubkey, /* token mint */
@@ -2198,7 +2204,7 @@ where
21982204
destination_account: &Pubkey,
21992205
source_authority: &Pubkey,
22002206
equality_proof_account: Option<&ProofAccount>,
2201-
ciphertext_validity_proof_account: Option<&ProofAccount>,
2207+
ciphertext_validity_proof_account_with_ciphertext: Option<&ProofAccountWithCiphertext>,
22022208
range_proof_account: Option<&ProofAccount>,
22032209
transfer_amount: u64,
22042210
account_info: Option<TransferAccountInfo>,
@@ -2220,46 +2226,65 @@ where
22202226
TransferAccountInfo::new(confidential_transfer_account)
22212227
};
22222228

2223-
let (equality_proof_data, ciphertext_validity_proof_data, range_proof_data) = if [
2224-
equality_proof_account,
2225-
ciphertext_validity_proof_account,
2226-
range_proof_account,
2227-
]
2228-
.iter()
2229-
.all(|proof_account| proof_account.is_some())
2230-
{
2231-
(None, None, None)
2232-
} else {
2233-
let TransferProofData {
2234-
equality_proof_data,
2235-
ciphertext_validity_proof_data,
2236-
range_proof_data,
2237-
} = account_info
2238-
.generate_split_transfer_proof_data(
2239-
transfer_amount,
2240-
source_elgamal_keypair,
2241-
source_aes_key,
2242-
destination_elgamal_pubkey,
2243-
auditor_elgamal_pubkey,
2244-
)
2245-
.map_err(|_| TokenError::ProofGeneration)?;
2229+
let (equality_proof_data, ciphertext_validity_proof_data_with_ciphertext, range_proof_data) =
2230+
if equality_proof_account.is_some()
2231+
&& ciphertext_validity_proof_account_with_ciphertext.is_some()
2232+
&& range_proof_account.is_some()
2233+
{
2234+
(None, None, None)
2235+
} else {
2236+
let TransferProofData {
2237+
equality_proof_data,
2238+
ciphertext_validity_proof_data_with_ciphertext,
2239+
range_proof_data,
2240+
} = account_info
2241+
.generate_split_transfer_proof_data(
2242+
transfer_amount,
2243+
source_elgamal_keypair,
2244+
source_aes_key,
2245+
destination_elgamal_pubkey,
2246+
auditor_elgamal_pubkey,
2247+
)
2248+
.map_err(|_| TokenError::ProofGeneration)?;
22462249

2247-
// if proof accounts are none, then proof data must be included as instruction
2248-
// data
2249-
let equality_proof_data = equality_proof_account
2250-
.is_none()
2251-
.then_some(equality_proof_data);
2252-
let ciphertext_validity_proof_data = ciphertext_validity_proof_account
2253-
.is_none()
2254-
.then_some(ciphertext_validity_proof_data);
2255-
let range_proof_data = range_proof_account.is_none().then_some(range_proof_data);
2250+
// if proof accounts are none, then proof data must be included as instruction
2251+
// data
2252+
let equality_proof_data = equality_proof_account
2253+
.is_none()
2254+
.then_some(equality_proof_data);
2255+
let ciphertext_validity_proof_data_with_ciphertext =
2256+
ciphertext_validity_proof_account_with_ciphertext
2257+
.is_none()
2258+
.then_some(ciphertext_validity_proof_data_with_ciphertext);
2259+
let range_proof_data = range_proof_account.is_none().then_some(range_proof_data);
22562260

2257-
(
2258-
equality_proof_data,
2259-
ciphertext_validity_proof_data,
2260-
range_proof_data,
2261-
)
2262-
};
2261+
(
2262+
equality_proof_data,
2263+
ciphertext_validity_proof_data_with_ciphertext,
2264+
range_proof_data,
2265+
)
2266+
};
2267+
2268+
let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) =
2269+
if let Some(proof_data_with_ciphertext) = ciphertext_validity_proof_data_with_ciphertext
2270+
{
2271+
(
2272+
proof_data_with_ciphertext.ciphertext_lo,
2273+
proof_data_with_ciphertext.ciphertext_hi,
2274+
)
2275+
} else {
2276+
// unwrap is safe as long as either `proof_data_with_ciphertext`,
2277+
// `proof_account_with_ciphertext` is `Some(..)`, which is guaranteed by the
2278+
// previous check
2279+
(
2280+
ciphertext_validity_proof_account_with_ciphertext
2281+
.unwrap()
2282+
.ciphertext_lo,
2283+
ciphertext_validity_proof_account_with_ciphertext
2284+
.unwrap()
2285+
.ciphertext_hi,
2286+
)
2287+
};
22632288

22642289
// cannot panic as long as either `proof_data` or `proof_account` is `Some(..)`,
22652290
// which is guaranteed by the previous check
@@ -2269,9 +2294,11 @@ where
22692294
1,
22702295
)
22712296
.unwrap();
2297+
let ciphertext_validity_proof_data =
2298+
ciphertext_validity_proof_data_with_ciphertext.map(|data| data.proof_data);
22722299
let ciphertext_validity_proof_location = Self::confidential_transfer_create_proof_location(
22732300
ciphertext_validity_proof_data.as_ref(),
2274-
ciphertext_validity_proof_account,
2301+
ciphertext_validity_proof_account_with_ciphertext.map(|account| &account.proof_account),
22752302
2,
22762303
)
22772304
.unwrap();
@@ -2292,6 +2319,8 @@ where
22922319
self.get_address(),
22932320
destination_account,
22942321
new_decryptable_available_balance.into(),
2322+
&transfer_amount_auditor_ciphertext_lo,
2323+
&transfer_amount_auditor_ciphertext_hi,
22952324
source_authority,
22962325
&multisig_signers,
22972326
equality_proof_location,
@@ -2526,7 +2555,9 @@ where
25262555
destination_account: &Pubkey,
25272556
source_authority: &Pubkey,
25282557
equality_proof_account: Option<&ProofAccount>,
2529-
transfer_amount_ciphertext_validity_proof_account: Option<&ProofAccount>,
2558+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext: Option<
2559+
&ProofAccountWithCiphertext,
2560+
>,
25302561
percentage_with_cap_proof_account: Option<&ProofAccount>,
25312562
fee_ciphertext_validity_proof_account: Option<&ProofAccount>,
25322563
range_proof_account: Option<&ProofAccount>,
@@ -2555,26 +2586,22 @@ where
25552586

25562587
let (
25572588
equality_proof_data,
2558-
transfer_amount_ciphertext_validity_proof_data,
2589+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
25592590
percentage_with_cap_proof_data,
25602591
fee_ciphertext_validity_proof_data,
25612592
range_proof_data,
2562-
) = if [
2563-
equality_proof_account,
2564-
transfer_amount_ciphertext_validity_proof_account,
2565-
percentage_with_cap_proof_account,
2566-
fee_ciphertext_validity_proof_account,
2567-
range_proof_account,
2568-
]
2569-
.iter()
2570-
.all(|proof_account| proof_account.is_some())
2593+
) = if equality_proof_account.is_some()
2594+
&& transfer_amount_ciphertext_validity_proof_account_with_ciphertext.is_some()
2595+
&& percentage_with_cap_proof_account.is_some()
2596+
&& fee_ciphertext_validity_proof_account.is_some()
2597+
&& range_proof_account.is_some()
25712598
{
25722599
// is all proofs come from accounts, then skip proof generation
25732600
(None, None, None, None, None)
25742601
} else {
25752602
let TransferWithFeeProofData {
25762603
equality_proof_data,
2577-
transfer_amount_ciphertext_validity_proof_data,
2604+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
25782605
percentage_with_cap_proof_data,
25792606
fee_ciphertext_validity_proof_data,
25802607
range_proof_data,
@@ -2594,10 +2621,10 @@ where
25942621
let equality_proof_data = equality_proof_account
25952622
.is_none()
25962623
.then_some(equality_proof_data);
2597-
let transfer_amount_ciphertext_validity_proof_data =
2598-
transfer_amount_ciphertext_validity_proof_account
2624+
let transfer_amount_ciphertext_validity_proof_data_with_ciphertext =
2625+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
25992626
.is_none()
2600-
.then_some(transfer_amount_ciphertext_validity_proof_data);
2627+
.then_some(transfer_amount_ciphertext_validity_proof_data_with_ciphertext);
26012628
let percentage_with_cap_proof_data = percentage_with_cap_proof_account
26022629
.is_none()
26032630
.then_some(percentage_with_cap_proof_data);
@@ -2608,13 +2635,35 @@ where
26082635

26092636
(
26102637
equality_proof_data,
2611-
transfer_amount_ciphertext_validity_proof_data,
2638+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
26122639
percentage_with_cap_proof_data,
26132640
fee_ciphertext_validity_proof_data,
26142641
range_proof_data,
26152642
)
26162643
};
26172644

2645+
let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) =
2646+
if let Some(proof_data_with_ciphertext) =
2647+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext
2648+
{
2649+
(
2650+
proof_data_with_ciphertext.ciphertext_lo,
2651+
proof_data_with_ciphertext.ciphertext_hi,
2652+
)
2653+
} else {
2654+
// unwrap is safe as long as either `proof_data_with_ciphertext`,
2655+
// `proof_account_with_ciphertext` is `Some(..)`, which is guaranteed by the
2656+
// previous check
2657+
(
2658+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
2659+
.unwrap()
2660+
.ciphertext_lo,
2661+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
2662+
.unwrap()
2663+
.ciphertext_hi,
2664+
)
2665+
};
2666+
26182667
// cannot panic as long as either `proof_data` or `proof_account` is `Some(..)`,
26192668
// which is guaranteed by the previous check
26202669
let equality_proof_location = Self::confidential_transfer_create_proof_location(
@@ -2623,10 +2672,14 @@ where
26232672
1,
26242673
)
26252674
.unwrap();
2675+
let transfer_amount_ciphertext_validity_proof_data =
2676+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext
2677+
.map(|data| data.proof_data);
26262678
let transfer_amount_ciphertext_validity_proof_location =
26272679
Self::confidential_transfer_create_proof_location(
26282680
transfer_amount_ciphertext_validity_proof_data.as_ref(),
2629-
transfer_amount_ciphertext_validity_proof_account,
2681+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
2682+
.map(|account| &account.proof_account),
26302683
2,
26312684
)
26322685
.unwrap();
@@ -2660,6 +2713,8 @@ where
26602713
self.get_address(),
26612714
destination_account,
26622715
new_decryptable_available_balance.into(),
2716+
&transfer_amount_auditor_ciphertext_lo,
2717+
&transfer_amount_auditor_ciphertext_hi,
26632718
source_authority,
26642719
&multisig_signers,
26652720
equality_proof_location,

0 commit comments

Comments
 (0)