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

Commit 8fc8f98

Browse files
committed
add CiphertextValidityProofWithCiphertext type
1 parent c77a50b commit 8fc8f98

File tree

11 files changed

+253
-194
lines changed

11 files changed

+253
-194
lines changed

token/client/src/token.rs

Lines changed: 92 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -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,11 +2204,9 @@ 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,
2204-
transfer_amount_auditor_ciphertext_lo: Option<&PodElGamalCiphertext>,
2205-
transfer_amount_auditor_ciphertext_hi: Option<&PodElGamalCiphertext>,
22062210
account_info: Option<TransferAccountInfo>,
22072211
source_elgamal_keypair: &ElGamalKeypair,
22082212
source_aes_key: &AeKey,
@@ -2222,71 +2226,63 @@ where
22222226
TransferAccountInfo::new(confidential_transfer_account)
22232227
};
22242228

2225-
let (equality_proof_data, ciphertext_validity_proof_data, range_proof_data) = if [
2226-
equality_proof_account,
2227-
ciphertext_validity_proof_account,
2228-
range_proof_account,
2229-
]
2230-
.iter()
2231-
.all(|proof_account| proof_account.is_some())
2232-
{
2233-
(None, None, None)
2234-
} else {
2235-
let TransferProofData {
2236-
equality_proof_data,
2237-
ciphertext_validity_proof_data,
2238-
range_proof_data,
2239-
} = account_info
2240-
.generate_split_transfer_proof_data(
2241-
transfer_amount,
2242-
source_elgamal_keypair,
2243-
source_aes_key,
2244-
destination_elgamal_pubkey,
2245-
auditor_elgamal_pubkey,
2246-
)
2247-
.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)?;
22482249

2249-
// if proof accounts are none, then proof data must be included as instruction
2250-
// data
2251-
let equality_proof_data = equality_proof_account
2252-
.is_none()
2253-
.then_some(equality_proof_data);
2254-
let ciphertext_validity_proof_data = ciphertext_validity_proof_account
2255-
.is_none()
2256-
.then_some(ciphertext_validity_proof_data);
2257-
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);
22582260

2259-
(
2260-
equality_proof_data,
2261-
ciphertext_validity_proof_data,
2262-
range_proof_data,
2263-
)
2264-
};
2261+
(
2262+
equality_proof_data,
2263+
ciphertext_validity_proof_data_with_ciphertext,
2264+
range_proof_data,
2265+
)
2266+
};
22652267

22662268
let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) =
2267-
if let Some(proof_data) = ciphertext_validity_proof_data {
2268-
let transfer_amount_auditor_ciphertext_lo = proof_data
2269-
.context_data()
2270-
.grouped_ciphertext_lo
2271-
.try_extract_ciphertext(2)
2272-
.map_err(|_| TokenError::ProofGeneration)?;
2273-
let transfer_amount_auditor_ciphertext_hi = proof_data
2274-
.context_data()
2275-
.grouped_ciphertext_hi
2276-
.try_extract_ciphertext(2)
2277-
.map_err(|_| TokenError::ProofGeneration)?;
2269+
if let Some(proof_data_with_ciphertext) = ciphertext_validity_proof_data_with_ciphertext
2270+
{
22782271
(
2279-
transfer_amount_auditor_ciphertext_lo,
2280-
transfer_amount_auditor_ciphertext_hi,
2272+
proof_data_with_ciphertext.ciphertext_lo,
2273+
proof_data_with_ciphertext.ciphertext_hi,
22812274
)
22822275
} else {
2283-
// the validity proof data is always generated unless
2284-
// `transfer_amount_auditor_ciphertext_lo` and
2285-
// `transfer_amount_auditor_ciphertext_hi` are `Some`, so it is
2286-
// safe to unwrap
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
22872279
(
2288-
*transfer_amount_auditor_ciphertext_lo.unwrap(),
2289-
*transfer_amount_auditor_ciphertext_hi.unwrap(),
2280+
ciphertext_validity_proof_account_with_ciphertext
2281+
.unwrap()
2282+
.ciphertext_lo,
2283+
ciphertext_validity_proof_account_with_ciphertext
2284+
.unwrap()
2285+
.ciphertext_hi,
22902286
)
22912287
};
22922288

@@ -2298,9 +2294,11 @@ where
22982294
1,
22992295
)
23002296
.unwrap();
2297+
let ciphertext_validity_proof_data =
2298+
ciphertext_validity_proof_data_with_ciphertext.map(|data| data.proof_data);
23012299
let ciphertext_validity_proof_location = Self::confidential_transfer_create_proof_location(
23022300
ciphertext_validity_proof_data.as_ref(),
2303-
ciphertext_validity_proof_account,
2301+
ciphertext_validity_proof_account_with_ciphertext.map(|account| &account.proof_account),
23042302
2,
23052303
)
23062304
.unwrap();
@@ -2557,13 +2555,13 @@ where
25572555
destination_account: &Pubkey,
25582556
source_authority: &Pubkey,
25592557
equality_proof_account: Option<&ProofAccount>,
2560-
transfer_amount_ciphertext_validity_proof_account: Option<&ProofAccount>,
2558+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext: Option<
2559+
&ProofAccountWithCiphertext,
2560+
>,
25612561
percentage_with_cap_proof_account: Option<&ProofAccount>,
25622562
fee_ciphertext_validity_proof_account: Option<&ProofAccount>,
25632563
range_proof_account: Option<&ProofAccount>,
25642564
transfer_amount: u64,
2565-
transfer_amount_auditor_ciphertext_lo: Option<&PodElGamalCiphertext>,
2566-
transfer_amount_auditor_ciphertext_hi: Option<&PodElGamalCiphertext>,
25672565
account_info: Option<TransferAccountInfo>,
25682566
source_elgamal_keypair: &ElGamalKeypair,
25692567
source_aes_key: &AeKey,
@@ -2588,26 +2586,22 @@ where
25882586

25892587
let (
25902588
equality_proof_data,
2591-
transfer_amount_ciphertext_validity_proof_data,
2589+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
25922590
percentage_with_cap_proof_data,
25932591
fee_ciphertext_validity_proof_data,
25942592
range_proof_data,
2595-
) = if [
2596-
equality_proof_account,
2597-
transfer_amount_ciphertext_validity_proof_account,
2598-
percentage_with_cap_proof_account,
2599-
fee_ciphertext_validity_proof_account,
2600-
range_proof_account,
2601-
]
2602-
.iter()
2603-
.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()
26042598
{
26052599
// is all proofs come from accounts, then skip proof generation
26062600
(None, None, None, None, None)
26072601
} else {
26082602
let TransferWithFeeProofData {
26092603
equality_proof_data,
2610-
transfer_amount_ciphertext_validity_proof_data,
2604+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
26112605
percentage_with_cap_proof_data,
26122606
fee_ciphertext_validity_proof_data,
26132607
range_proof_data,
@@ -2627,10 +2621,10 @@ where
26272621
let equality_proof_data = equality_proof_account
26282622
.is_none()
26292623
.then_some(equality_proof_data);
2630-
let transfer_amount_ciphertext_validity_proof_data =
2631-
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
26322626
.is_none()
2633-
.then_some(transfer_amount_ciphertext_validity_proof_data);
2627+
.then_some(transfer_amount_ciphertext_validity_proof_data_with_ciphertext);
26342628
let percentage_with_cap_proof_data = percentage_with_cap_proof_account
26352629
.is_none()
26362630
.then_some(percentage_with_cap_proof_data);
@@ -2641,37 +2635,32 @@ where
26412635

26422636
(
26432637
equality_proof_data,
2644-
transfer_amount_ciphertext_validity_proof_data,
2638+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext,
26452639
percentage_with_cap_proof_data,
26462640
fee_ciphertext_validity_proof_data,
26472641
range_proof_data,
26482642
)
26492643
};
26502644

26512645
let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) =
2652-
if let Some(proof_data) = transfer_amount_ciphertext_validity_proof_data {
2653-
let transfer_amount_auditor_ciphertext_lo = proof_data
2654-
.context_data()
2655-
.grouped_ciphertext_lo
2656-
.try_extract_ciphertext(2)
2657-
.map_err(|_| TokenError::ProofGeneration)?;
2658-
let transfer_amount_auditor_ciphertext_hi = proof_data
2659-
.context_data()
2660-
.grouped_ciphertext_hi
2661-
.try_extract_ciphertext(2)
2662-
.map_err(|_| TokenError::ProofGeneration)?;
2646+
if let Some(proof_data_with_ciphertext) =
2647+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext
2648+
{
26632649
(
2664-
transfer_amount_auditor_ciphertext_lo,
2665-
transfer_amount_auditor_ciphertext_hi,
2650+
proof_data_with_ciphertext.ciphertext_lo,
2651+
proof_data_with_ciphertext.ciphertext_hi,
26662652
)
26672653
} else {
2668-
// the validity proof data is always generated unless
2669-
// `transfer_amount_auditor_ciphertext_lo` and
2670-
// `transfer_amount_auditor_ciphertext_hi` are `Some`, so it is
2671-
// safe to unwrap
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
26722657
(
2673-
*transfer_amount_auditor_ciphertext_lo.unwrap(),
2674-
*transfer_amount_auditor_ciphertext_hi.unwrap(),
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,
26752664
)
26762665
};
26772666

@@ -2683,10 +2672,14 @@ where
26832672
1,
26842673
)
26852674
.unwrap();
2675+
let transfer_amount_ciphertext_validity_proof_data =
2676+
transfer_amount_ciphertext_validity_proof_data_with_ciphertext
2677+
.map(|data| data.proof_data);
26862678
let transfer_amount_ciphertext_validity_proof_location =
26872679
Self::confidential_transfer_create_proof_location(
26882680
transfer_amount_ciphertext_validity_proof_data.as_ref(),
2689-
transfer_amount_ciphertext_validity_proof_account,
2681+
transfer_amount_ciphertext_validity_proof_account_with_ciphertext
2682+
.map(|account| &account.proof_account),
26902683
2,
26912684
)
26922685
.unwrap();

token/confidential-transfer/proof-generation/src/burn.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use {
22
crate::{
33
encryption::BurnAmountCiphertext, errors::TokenProofGenerationError,
4-
try_combine_lo_hi_ciphertexts, try_split_u64,
4+
try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext,
55
},
66
solana_zk_sdk::{
77
encryption::{
@@ -11,7 +11,7 @@ use {
1111
},
1212
zk_elgamal_proof_program::proof_data::{
1313
BatchedGroupedCiphertext3HandlesValidityProofData, BatchedRangeProofU128Data,
14-
CiphertextCommitmentEqualityProofData,
14+
CiphertextCommitmentEqualityProofData, ZkProofData,
1515
},
1616
},
1717
};
@@ -25,7 +25,7 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16;
2525
/// The proof data required for a confidential burn instruction
2626
pub struct BurnProofData {
2727
pub equality_proof_data: CiphertextCommitmentEqualityProofData,
28-
pub ciphertext_validity_proof_data: BatchedGroupedCiphertext3HandlesValidityProofData,
28+
pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext,
2929
pub range_proof_data: BatchedRangeProofU128Data,
3030
}
3131

@@ -113,6 +113,24 @@ pub fn burn_split_proof_data(
113113
)
114114
.map_err(TokenProofGenerationError::from)?;
115115

116+
let burn_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data
117+
.context_data()
118+
.grouped_ciphertext_lo
119+
.try_extract_ciphertext(2)
120+
.map_err(|_| TokenProofGenerationError::CiphertextExtraction)?;
121+
122+
let burn_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data
123+
.context_data()
124+
.grouped_ciphertext_hi
125+
.try_extract_ciphertext(2)
126+
.map_err(|_| TokenProofGenerationError::CiphertextExtraction)?;
127+
128+
let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext {
129+
proof_data: ciphertext_validity_proof_data,
130+
ciphertext_lo: burn_amount_auditor_ciphertext_lo,
131+
ciphertext_hi: burn_amount_auditor_ciphertext_hi,
132+
};
133+
116134
// generate range proof data
117135
let (padding_commitment, padding_opening) = Pedersen::new(0_u64);
118136
let range_proof_data = BatchedRangeProofU128Data::new(
@@ -140,7 +158,7 @@ pub fn burn_split_proof_data(
140158

141159
Ok(BurnProofData {
142160
equality_proof_data,
143-
ciphertext_validity_proof_data,
161+
ciphertext_validity_proof_data_with_ciphertext,
144162
range_proof_data,
145163
})
146164
}

token/confidential-transfer/proof-generation/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ pub enum TokenProofGenerationError {
1010
IllegalAmountBitLength,
1111
#[error("fee calculation failed")]
1212
FeeCalculation,
13+
#[error("ciphertext extraction failed")]
14+
CiphertextExtraction,
1315
}

token/confidential-transfer/proof-generation/src/lib.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use {
22
curve25519_dalek::scalar::Scalar,
3-
solana_zk_sdk::encryption::{
4-
elgamal::ElGamalCiphertext,
5-
pedersen::{PedersenCommitment, PedersenOpening},
3+
solana_zk_sdk::{
4+
encryption::{
5+
elgamal::ElGamalCiphertext,
6+
pedersen::{PedersenCommitment, PedersenOpening},
7+
pod::elgamal::PodElGamalCiphertext,
8+
},
9+
zk_elgamal_proof_program::proof_data::BatchedGroupedCiphertext3HandlesValidityProofData,
610
},
711
};
812

@@ -87,3 +91,10 @@ pub fn try_combine_lo_hi_openings(
8791
let two_power = 1_u64.checked_shl(bit_length as u32)?;
8892
Some(opening_lo + opening_hi * Scalar::from(two_power))
8993
}
94+
95+
#[derive(Clone, Copy)]
96+
pub struct CiphertextValidityProofWithCiphertext {
97+
pub proof_data: BatchedGroupedCiphertext3HandlesValidityProofData,
98+
pub ciphertext_lo: PodElGamalCiphertext,
99+
pub ciphertext_hi: PodElGamalCiphertext,
100+
}

0 commit comments

Comments
 (0)