From 0f36ed832b45fe49088870e7c8e95da74ff18783 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Mon, 11 Nov 2024 16:58:49 +0900 Subject: [PATCH 01/12] add auditor ciphertext to transfer instruction data --- token/client/src/token.rs | 62 ++++++++++++++++++- .../tests/confidential_transfer.rs | 60 ++++++++++++++++++ .../tests/confidential_transfer_fee.rs | 6 ++ .../program-2022-test/tests/transfer_hook.rs | 2 + .../confidential_transfer/instruction.rs | 28 +++++++++ .../confidential_transfer/processor.rs | 55 ++++++++++++++++ token/program-2022/src/serialization.rs | 49 ++++++++++++++- 7 files changed, 259 insertions(+), 3 deletions(-) diff --git a/token/client/src/token.rs b/token/client/src/token.rs index 33bab151499..a6e3561ef0e 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -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, @@ -2201,6 +2201,8 @@ where ciphertext_validity_proof_account: Option<&ProofAccount>, range_proof_account: Option<&ProofAccount>, transfer_amount: u64, + transfer_amount_auditor_ciphertext_lo: Option<&PodElGamalCiphertext>, + transfer_amount_auditor_ciphertext_hi: Option<&PodElGamalCiphertext>, account_info: Option, source_elgamal_keypair: &ElGamalKeypair, source_aes_key: &AeKey, @@ -2261,6 +2263,32 @@ where ) }; + let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) = + if let Some(proof_data) = ciphertext_validity_proof_data { + let transfer_amount_auditor_ciphertext_lo = proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|_| TokenError::ProofGeneration)?; + let transfer_amount_auditor_ciphertext_hi = proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|_| TokenError::ProofGeneration)?; + ( + transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi, + ) + } else { + // the validity proof data is always generated unless + // `transfer_amount_auditor_ciphertext_lo` and `transfer_amount_auditor_ciphertext_hi` + // are `Some`, so it is safe to unwrap + ( + *transfer_amount_auditor_ciphertext_lo.unwrap(), + *transfer_amount_auditor_ciphertext_hi.unwrap(), + ) + }; + // 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( @@ -2292,6 +2320,8 @@ where self.get_address(), destination_account, new_decryptable_available_balance.into(), + &transfer_amount_auditor_ciphertext_lo.into(), + &transfer_amount_auditor_ciphertext_hi.into(), source_authority, &multisig_signers, equality_proof_location, @@ -2531,6 +2561,8 @@ where fee_ciphertext_validity_proof_account: Option<&ProofAccount>, range_proof_account: Option<&ProofAccount>, transfer_amount: u64, + transfer_amount_auditor_ciphertext_lo: Option<&PodElGamalCiphertext>, + transfer_amount_auditor_ciphertext_hi: Option<&PodElGamalCiphertext>, account_info: Option, source_elgamal_keypair: &ElGamalKeypair, source_aes_key: &AeKey, @@ -2615,6 +2647,32 @@ where ) }; + let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) = + if let Some(proof_data) = transfer_amount_ciphertext_validity_proof_data { + let transfer_amount_auditor_ciphertext_lo = proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|_| TokenError::ProofGeneration)?; + let transfer_amount_auditor_ciphertext_hi = proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|_| TokenError::ProofGeneration)?; + ( + transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi, + ) + } else { + // the validity proof data is always generated unless + // `transfer_amount_auditor_ciphertext_lo` and `transfer_amount_auditor_ciphertext_hi` + // are `Some`, so it is safe to unwrap + ( + *transfer_amount_auditor_ciphertext_lo.unwrap(), + *transfer_amount_auditor_ciphertext_hi.unwrap(), + ) + }; + // 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( @@ -2660,6 +2718,8 @@ where self.get_address(), destination_account, new_decryptable_available_balance.into(), + &transfer_amount_auditor_ciphertext_lo.into(), + &transfer_amount_auditor_ciphertext_hi.into(), source_authority, &multisig_signers, equality_proof_location, diff --git a/token/program-2022-test/tests/confidential_transfer.rs b/token/program-2022-test/tests/confidential_transfer.rs index 7c86f2f93d3..d322230d572 100644 --- a/token/program-2022-test/tests/confidential_transfer.rs +++ b/token/program-2022-test/tests/confidential_transfer.rs @@ -1321,6 +1321,8 @@ async fn confidential_transfer_with_option( None, transfer_amount, None, + None, + None, source_elgamal_keypair, source_aes_key, destination_elgamal_pubkey, @@ -1350,6 +1352,17 @@ async fn confidential_transfer_with_option( ) .unwrap(); + let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .unwrap(); + let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .unwrap(); + let equality_proof_record_account = Keypair::new(); let ciphertext_validity_proof_record_account = Keypair::new(); let range_proof_record_account = Keypair::new(); @@ -1418,6 +1431,8 @@ async fn confidential_transfer_with_option( Some(&ciphertext_validity_proof_account), Some(&range_proof_account), transfer_amount, + Some(&transfer_amount_auditor_ciphertext_lo), + Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, @@ -1480,6 +1495,17 @@ async fn confidential_transfer_with_option( ) .unwrap(); + let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .unwrap(); + let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .unwrap(); + let equality_proof_context_account = Keypair::new(); let ciphertext_validity_proof_context_account = Keypair::new(); let range_proof_context_account = Keypair::new(); @@ -1542,6 +1568,8 @@ async fn confidential_transfer_with_option( Some(&ciphertext_validity_proof_context_proof_account), Some(&range_proof_context_proof_account), transfer_amount, + Some(&transfer_amount_auditor_ciphertext_lo), + Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, @@ -1872,6 +1900,8 @@ async fn confidential_transfer_with_fee_with_option( None, transfer_amount, None, + None, + None, source_elgamal_keypair, source_aes_key, destination_elgamal_pubkey, @@ -1909,6 +1939,19 @@ async fn confidential_transfer_with_fee_with_option( ) .unwrap(); + let transfer_amount_auditor_ciphertext_lo = + transfer_amount_ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .unwrap(); + let transfer_amount_auditor_ciphertext_hi = + transfer_amount_ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .unwrap(); + let equality_proof_record_account = Keypair::new(); let transfer_amount_ciphertext_validity_proof_record_account = Keypair::new(); let fee_sigma_proof_record_account = Keypair::new(); @@ -2013,6 +2056,8 @@ async fn confidential_transfer_with_fee_with_option( Some(&fee_ciphertext_validity_proof_account), Some(&range_proof_account), transfer_amount, + Some(&transfer_amount_auditor_ciphertext_lo), + Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, @@ -2103,6 +2148,19 @@ async fn confidential_transfer_with_fee_with_option( ) .unwrap(); + let transfer_amount_auditor_ciphertext_lo = + transfer_amount_ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .unwrap(); + let transfer_amount_auditor_ciphertext_hi = + transfer_amount_ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .unwrap(); + let equality_proof_context_account = Keypair::new(); let transfer_amount_ciphertext_validity_proof_context_account = Keypair::new(); let percentage_with_cap_proof_context_account = Keypair::new(); @@ -2200,6 +2258,8 @@ async fn confidential_transfer_with_fee_with_option( Some(&fee_ciphertext_validity_proof_context_proof_account), Some(&range_proof_context_proof_account), transfer_amount, + Some(&transfer_amount_auditor_ciphertext_lo), + Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, diff --git a/token/program-2022-test/tests/confidential_transfer_fee.rs b/token/program-2022-test/tests/confidential_transfer_fee.rs index c2664525c5f..4e5f636273a 100644 --- a/token/program-2022-test/tests/confidential_transfer_fee.rs +++ b/token/program-2022-test/tests/confidential_transfer_fee.rs @@ -690,6 +690,8 @@ async fn confidential_transfer_withdraw_withheld_tokens_from_mint_with_option( None, 100, None, + None, + None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), @@ -1016,6 +1018,8 @@ async fn confidential_transfer_withdraw_withheld_tokens_from_accounts_with_optio None, 100, None, + None, + None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), @@ -1155,6 +1159,8 @@ async fn confidential_transfer_harvest_withheld_tokens_to_mint() { None, 100, None, + None, + None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), diff --git a/token/program-2022-test/tests/transfer_hook.rs b/token/program-2022-test/tests/transfer_hook.rs index 32f929857a4..30c247bb545 100644 --- a/token/program-2022-test/tests/transfer_hook.rs +++ b/token/program-2022-test/tests/transfer_hook.rs @@ -1004,6 +1004,8 @@ async fn success_confidential_transfer() { None, amount, None, + None, + None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), diff --git a/token/program-2022/src/extension/confidential_transfer/instruction.rs b/token/program-2022/src/extension/confidential_transfer/instruction.rs index a6e07793800..bd4b8c64c4f 100644 --- a/token/program-2022/src/extension/confidential_transfer/instruction.rs +++ b/token/program-2022/src/extension/confidential_transfer/instruction.rs @@ -619,6 +619,12 @@ pub struct TransferInstructionData { /// The new source decryptable balance if the transfer succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_source_decryptable_available_balance: DecryptableBalance, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub transfer_amount_auditor_ciphertext_lo: PodElGamalCiphertext, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub transfer_amount_auditor_ciphertext_hi: PodElGamalCiphertext, /// Relative location of the /// `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction /// to the `Transfer` instruction in the transaction. If the offset is @@ -658,6 +664,12 @@ pub struct TransferWithFeeInstructionData { /// The new source decryptable balance if the transfer succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_source_decryptable_available_balance: DecryptableBalance, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub transfer_amount_auditor_ciphertext_lo: PodElGamalCiphertext, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub transfer_amount_auditor_ciphertext_hi: PodElGamalCiphertext, /// Relative location of the /// `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction /// to the `TransferWithFee` instruction in the transaction. If the offset @@ -1151,6 +1163,8 @@ pub fn inner_transfer( mint: &Pubkey, destination_token_account: &Pubkey, new_source_decryptable_available_balance: DecryptableBalance, + transfer_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + transfer_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], equality_proof_data_location: ProofLocation, @@ -1231,6 +1245,8 @@ pub fn inner_transfer( ConfidentialTransferInstruction::Transfer, &TransferInstructionData { new_source_decryptable_available_balance, + transfer_amount_auditor_ciphertext_lo: *transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi: *transfer_amount_auditor_ciphertext_hi, equality_proof_instruction_offset, ciphertext_validity_proof_instruction_offset, range_proof_instruction_offset, @@ -1246,6 +1262,8 @@ pub fn transfer( mint: &Pubkey, destination_token_account: &Pubkey, new_source_decryptable_available_balance: DecryptableBalance, + transfer_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + transfer_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], equality_proof_data_location: ProofLocation, @@ -1260,6 +1278,8 @@ pub fn transfer( mint, destination_token_account, new_source_decryptable_available_balance, + transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi, authority, multisig_signers, equality_proof_data_location, @@ -1484,6 +1504,8 @@ pub fn inner_transfer_with_fee( mint: &Pubkey, destination_token_account: &Pubkey, new_source_decryptable_available_balance: DecryptableBalance, + transfer_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + transfer_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], equality_proof_data_location: ProofLocation, @@ -1597,6 +1619,8 @@ pub fn inner_transfer_with_fee( ConfidentialTransferInstruction::TransferWithFee, &TransferWithFeeInstructionData { new_source_decryptable_available_balance, + transfer_amount_auditor_ciphertext_lo: *transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi: *transfer_amount_auditor_ciphertext_hi, equality_proof_instruction_offset, transfer_amount_ciphertext_validity_proof_instruction_offset, fee_sigma_proof_instruction_offset, @@ -1614,6 +1638,8 @@ pub fn transfer_with_fee( mint: &Pubkey, destination_token_account: &Pubkey, new_source_decryptable_available_balance: DecryptableBalance, + transfer_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + transfer_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], equality_proof_data_location: ProofLocation, @@ -1632,6 +1658,8 @@ pub fn transfer_with_fee( mint, destination_token_account, new_source_decryptable_available_balance, + transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi, authority, multisig_signers, equality_proof_data_location, diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs index c387dedff1f..64851da252d 100644 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer/processor.rs @@ -591,6 +591,8 @@ fn process_transfer( program_id: &Pubkey, accounts: &[AccountInfo], new_source_decryptable_available_balance: DecryptableBalance, + transfer_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + transfer_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, equality_proof_instruction_offset: i64, transfer_amount_ciphertext_validity_proof_instruction_offset: i64, fee_sigma_proof_instruction_offset: Option, @@ -643,6 +645,22 @@ fn process_transfer( return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } + let proof_context_auditor_ciphertext_lo = proof_context + .ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + let proof_context_auditor_ciphertext_hi = proof_context + .ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + + check_auditor_ciphertext( + transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi, + &proof_context_auditor_ciphertext_lo, + &proof_context_auditor_ciphertext_hi, + )?; + process_source_for_transfer( program_id, source_account_info, @@ -708,6 +726,22 @@ fn process_transfer( return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } + let proof_context_auditor_ciphertext_lo = proof_context + .ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + let proof_context_auditor_ciphertext_hi = proof_context + .ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + + check_auditor_ciphertext( + transfer_amount_auditor_ciphertext_lo, + transfer_amount_auditor_ciphertext_hi, + &proof_context_auditor_ciphertext_lo, + &proof_context_auditor_ciphertext_hi, + )?; + process_source_for_transfer_with_fee( program_id, source_account_info, @@ -767,6 +801,23 @@ fn process_transfer( Ok(()) } +/// Check instruction data and proof data auditor ciphertext consistency +#[cfg(feature = "zk-ops")] +fn check_auditor_ciphertext( + instruction_data_auditor_ciphertext_lo: &PodElGamalCiphertext, + instruction_data_auditor_ciphertext_hi: &PodElGamalCiphertext, + proof_context_auditor_ciphertext_lo: &PodElGamalCiphertext, + proof_context_auditor_ciphertext_hi: &PodElGamalCiphertext, +) -> ProgramResult { + if instruction_data_auditor_ciphertext_lo != proof_context_auditor_ciphertext_lo { + return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); + } + if instruction_data_auditor_ciphertext_hi != proof_context_auditor_ciphertext_hi { + return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); + } + Ok(()) +} + /// Processes the changes for the sending party of a confidential transfer #[cfg(feature = "zk-ops")] fn process_source_for_transfer( @@ -1291,6 +1342,8 @@ pub(crate) fn process_instruction( program_id, accounts, data.new_source_decryptable_available_balance, + &data.transfer_amount_auditor_ciphertext_lo, + &data.transfer_amount_auditor_ciphertext_hi, data.equality_proof_instruction_offset as i64, data.ciphertext_validity_proof_instruction_offset as i64, None, @@ -1341,6 +1394,8 @@ pub(crate) fn process_instruction( program_id, accounts, data.new_source_decryptable_available_balance, + &data.transfer_amount_auditor_ciphertext_lo, + &data.transfer_amount_auditor_ciphertext_hi, data.equality_proof_instruction_offset as i64, data.transfer_amount_ciphertext_validity_proof_instruction_offset as i64, Some(data.fee_sigma_proof_instruction_offset as i64), diff --git a/token/program-2022/src/serialization.rs b/token/program-2022/src/serialization.rs index 74d4f642adb..8d337c1903d 100644 --- a/token/program-2022/src/serialization.rs +++ b/token/program-2022/src/serialization.rs @@ -76,7 +76,7 @@ pub mod coption_fromstr { } } -/// helper to ser/deser AeCiphertext values +/// helper to ser/deser PodAeCiphertext values pub mod aeciphertext_fromstr { use { serde::{ @@ -121,7 +121,7 @@ pub mod aeciphertext_fromstr { } } -/// helper to ser/deser pod::ElGamalPubkey values +/// helper to ser/deser PodElGamalPubkey values pub mod elgamalpubkey_fromstr { use { serde::{ @@ -165,3 +165,48 @@ pub mod elgamalpubkey_fromstr { d.deserialize_str(ElGamalPubkeyVisitor) } } + +/// helper to ser/deser PodElGamalCiphertext values +pub mod elgamalciphertext_fromstr { + use { + serde::{ + de::{Error, Visitor}, + Deserializer, Serializer, + }, + solana_zk_sdk::encryption::pod::elgamal::PodElGamalCiphertext, + std::{fmt, str::FromStr}, + }; + + /// serialize ElGamalCiphertext values supporting Display trait + pub fn serialize(x: &PodElGamalCiphertext, s: S) -> Result + where + S: Serializer, + { + s.serialize_str(&x.to_string()) + } + + struct ElGamalCiphertextVisitor; + + impl<'de> Visitor<'de> for ElGamalCiphertextVisitor { + type Value = PodElGamalCiphertext; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a FromStr type") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + FromStr::from_str(v).map_err(Error::custom) + } + } + + /// deserialize ElGamalCiphertext values from str + pub fn deserialize<'de, D>(d: D) -> Result + where + D: Deserializer<'de>, + { + d.deserialize_str(ElGamalCiphertextVisitor) + } +} From 95b889e24dcc178e3318bbb680132595fba43071 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Mon, 11 Nov 2024 17:22:25 +0900 Subject: [PATCH 02/12] add auditor ciphertext to confidential mint and burn instruction data --- .../confidential_mint_burn/instruction.rs | 25 ++++++++++- .../confidential_mint_burn/processor.rs | 42 ++++++++++++++++--- .../confidential_transfer/processor.rs | 19 +-------- token/program-2022/src/lib.rs | 25 ++++++++++- 4 files changed, 85 insertions(+), 26 deletions(-) diff --git a/token/program-2022/src/extension/confidential_mint_burn/instruction.rs b/token/program-2022/src/extension/confidential_mint_burn/instruction.rs index b4abbb755b4..ad268fdbecf 100644 --- a/token/program-2022/src/extension/confidential_mint_burn/instruction.rs +++ b/token/program-2022/src/extension/confidential_mint_burn/instruction.rs @@ -16,7 +16,10 @@ use { program_error::ProgramError, pubkey::Pubkey, }, - solana_zk_sdk::encryption::pod::{auth_encryption::PodAeCiphertext, elgamal::PodElGamalPubkey}, + solana_zk_sdk::encryption::pod::{ + auth_encryption::PodAeCiphertext, + elgamal::{PodElGamalCiphertext, PodElGamalPubkey}, + }, }; #[cfg(not(target_os = "solana"))] use { @@ -229,6 +232,12 @@ pub struct MintInstructionData { /// The new decryptable supply if the mint succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_decryptable_supply: PodAeCiphertext, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub mint_amount_auditor_ciphertext_lo: PodElGamalCiphertext, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub mint_amount_auditor_ciphertext_hi: PodElGamalCiphertext, /// Relative location of the /// `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction /// to the `ConfidentialMint` instruction in the transaction. 0 if the @@ -254,6 +263,12 @@ pub struct BurnInstructionData { /// The new decryptable balance of the burner if the burn succeeds #[cfg_attr(feature = "serde-traits", serde(with = "aeciphertext_fromstr"))] pub new_decryptable_available_balance: DecryptableBalance, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub burn_amount_auditor_ciphertext_lo: PodElGamalCiphertext, + /// The transfer amount encrypted under the auditor ElGamal public key + #[cfg_attr(feature = "serde-traits", serde(with = "elgamalciphertext_fromstr"))] + pub burn_amount_auditor_ciphertext_hi: PodElGamalCiphertext, /// Relative location of the /// `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction /// to the `ConfidentialMint` instruction in the transaction. 0 if the @@ -391,6 +406,8 @@ pub fn confidential_mint_with_split_proofs( token_account: &Pubkey, mint: &Pubkey, supply_elgamal_pubkey: Option, + mint_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + mint_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], equality_proof_location: ProofLocation, @@ -455,6 +472,8 @@ pub fn confidential_mint_with_split_proofs( ConfidentialMintBurnInstruction::Mint, &MintInstructionData { new_decryptable_supply: new_decryptable_supply.into(), + mint_amount_auditor_ciphertext_lo: *mint_amount_auditor_ciphertext_lo, + mint_amount_auditor_ciphertext_hi: *mint_amount_auditor_ciphertext_hi, equality_proof_instruction_offset, ciphertext_validity_proof_instruction_offset, range_proof_instruction_offset, @@ -475,6 +494,8 @@ pub fn confidential_burn_with_split_proofs( mint: &Pubkey, supply_elgamal_pubkey: Option, new_decryptable_available_balance: DecryptableBalance, + burn_amount_auditor_ciphertext_lo: &PodElGamalCiphertext, + burn_amount_auditor_ciphertext_hi: &PodElGamalCiphertext, authority: &Pubkey, multisig_signers: &[&Pubkey], equality_proof_location: ProofLocation, @@ -537,6 +558,8 @@ pub fn confidential_burn_with_split_proofs( ConfidentialMintBurnInstruction::Burn, &BurnInstructionData { new_decryptable_available_balance, + burn_amount_auditor_ciphertext_lo: *burn_amount_auditor_ciphertext_lo, + burn_amount_auditor_ciphertext_hi: *burn_amount_auditor_ciphertext_hi, equality_proof_instruction_offset, ciphertext_validity_proof_instruction_offset, range_proof_instruction_offset, diff --git a/token/program-2022/src/extension/confidential_mint_burn/processor.rs b/token/program-2022/src/extension/confidential_mint_burn/processor.rs index f0697337783..90698a4be4c 100644 --- a/token/program-2022/src/extension/confidential_mint_burn/processor.rs +++ b/token/program-2022/src/extension/confidential_mint_burn/processor.rs @@ -2,7 +2,7 @@ use spl_token_confidential_transfer_ciphertext_arithmetic as ciphertext_arithmetic; use { crate::{ - check_program_account, + check_auditor_ciphertext, check_program_account, error::TokenError, extension::{ confidential_mint_burn::{ @@ -210,12 +210,28 @@ fn process_confidential_mint( } } + let proof_context_auditor_ciphertext_lo = proof_context + .mint_amount_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + let proof_context_auditor_ciphertext_hi = proof_context + .mint_amount_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + + check_auditor_ciphertext( + &data.mint_amount_auditor_ciphertext_lo, + &data.mint_amount_auditor_ciphertext_hi, + &proof_context_auditor_ciphertext_lo, + &proof_context_auditor_ciphertext_hi, + )?; + confidential_transfer_account.pending_balance_lo = ciphertext_arithmetic::add( &confidential_transfer_account.pending_balance_lo, &proof_context .mint_amount_ciphertext_lo .try_extract_ciphertext(0) - .map_err(|_| ProgramError::InvalidAccountData)?, + .map_err(|e| -> TokenError { e.into() })?, ) .ok_or(TokenError::CiphertextArithmeticFailed)?; confidential_transfer_account.pending_balance_hi = ciphertext_arithmetic::add( @@ -223,7 +239,7 @@ fn process_confidential_mint( &proof_context .mint_amount_ciphertext_hi .try_extract_ciphertext(0) - .map_err(|_| ProgramError::InvalidAccountData)?, + .map_err(|e| -> TokenError { e.into() })?, ) .ok_or(TokenError::CiphertextArithmeticFailed)?; @@ -311,14 +327,30 @@ fn process_confidential_burn( return Err(TokenError::ConfidentialTransferElGamalPubkeyMismatch.into()); } + let proof_context_auditor_ciphertext_lo = proof_context + .burn_amount_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + let proof_context_auditor_ciphertext_hi = proof_context + .burn_amount_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|e| -> TokenError { e.into() })?; + + check_auditor_ciphertext( + &data.burn_amount_auditor_ciphertext_lo, + &data.burn_amount_auditor_ciphertext_hi, + &proof_context_auditor_ciphertext_lo, + &proof_context_auditor_ciphertext_hi, + )?; + let burn_amount_lo = &proof_context .burn_amount_ciphertext_lo .try_extract_ciphertext(0) - .map_err(|_| ProgramError::InvalidAccountData)?; + .map_err(|e| -> TokenError { e.into() })?; let burn_amount_hi = &proof_context .burn_amount_ciphertext_hi .try_extract_ciphertext(0) - .map_err(|_| ProgramError::InvalidAccountData)?; + .map_err(|e| -> TokenError { e.into() })?; let new_source_available_balance = ciphertext_arithmetic::subtract_with_lo_hi( &confidential_transfer_account.available_balance, diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs index 64851da252d..5d437322675 100644 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer/processor.rs @@ -7,7 +7,7 @@ use { }; use { crate::{ - check_elgamal_registry_program_account, check_program_account, + check_auditor_ciphertext, check_elgamal_registry_program_account, check_program_account, error::TokenError, extension::{ confidential_transfer::{instruction::*, verify_proof::*, *}, @@ -801,23 +801,6 @@ fn process_transfer( Ok(()) } -/// Check instruction data and proof data auditor ciphertext consistency -#[cfg(feature = "zk-ops")] -fn check_auditor_ciphertext( - instruction_data_auditor_ciphertext_lo: &PodElGamalCiphertext, - instruction_data_auditor_ciphertext_hi: &PodElGamalCiphertext, - proof_context_auditor_ciphertext_lo: &PodElGamalCiphertext, - proof_context_auditor_ciphertext_hi: &PodElGamalCiphertext, -) -> ProgramResult { - if instruction_data_auditor_ciphertext_lo != proof_context_auditor_ciphertext_lo { - return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); - } - if instruction_data_auditor_ciphertext_hi != proof_context_auditor_ciphertext_hi { - return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); - } - Ok(()) -} - /// Processes the changes for the sending party of a confidential transfer #[cfg(feature = "zk-ops")] fn process_source_for_transfer( diff --git a/token/program-2022/src/lib.rs b/token/program-2022/src/lib.rs index d413d5903a5..d803ff4a0ba 100644 --- a/token/program-2022/src/lib.rs +++ b/token/program-2022/src/lib.rs @@ -23,8 +23,12 @@ mod entrypoint; // Export current sdk types for downstream users building with a different sdk // version -use solana_program::{ - entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, system_program, +use { + error::TokenError, + solana_program::{ + entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, system_program, + }, + solana_zk_sdk::encryption::pod::elgamal::PodElGamalCiphertext, }; pub use {solana_program, solana_zk_sdk}; @@ -139,3 +143,20 @@ pub(crate) fn check_elgamal_registry_program_account( } Ok(()) } + +/// Check instruction data and proof data auditor ciphertext consistency +#[cfg(feature = "zk-ops")] +pub(crate) fn check_auditor_ciphertext( + instruction_data_auditor_ciphertext_lo: &PodElGamalCiphertext, + instruction_data_auditor_ciphertext_hi: &PodElGamalCiphertext, + proof_context_auditor_ciphertext_lo: &PodElGamalCiphertext, + proof_context_auditor_ciphertext_hi: &PodElGamalCiphertext, +) -> ProgramResult { + if instruction_data_auditor_ciphertext_lo != proof_context_auditor_ciphertext_lo { + return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); + } + if instruction_data_auditor_ciphertext_hi != proof_context_auditor_ciphertext_hi { + return Err(TokenError::ConfidentialTransferBalanceMismatch.into()); + } + Ok(()) +} From 2076cec897dcb182ee4c7ea5d2ed60e8e1dfa712 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Mon, 11 Nov 2024 17:23:47 +0900 Subject: [PATCH 03/12] cargo fmt --- token/client/src/token.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/token/client/src/token.rs b/token/client/src/token.rs index a6e3561ef0e..8aaa6800941 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -2281,8 +2281,9 @@ where ) } else { // the validity proof data is always generated unless - // `transfer_amount_auditor_ciphertext_lo` and `transfer_amount_auditor_ciphertext_hi` - // are `Some`, so it is safe to unwrap + // `transfer_amount_auditor_ciphertext_lo` and + // `transfer_amount_auditor_ciphertext_hi` are `Some`, so it is + // safe to unwrap ( *transfer_amount_auditor_ciphertext_lo.unwrap(), *transfer_amount_auditor_ciphertext_hi.unwrap(), @@ -2665,8 +2666,9 @@ where ) } else { // the validity proof data is always generated unless - // `transfer_amount_auditor_ciphertext_lo` and `transfer_amount_auditor_ciphertext_hi` - // are `Some`, so it is safe to unwrap + // `transfer_amount_auditor_ciphertext_lo` and + // `transfer_amount_auditor_ciphertext_hi` are `Some`, so it is + // safe to unwrap ( *transfer_amount_auditor_ciphertext_lo.unwrap(), *transfer_amount_auditor_ciphertext_hi.unwrap(), From 0051544ae1770b115b893c54a99b41afac526a51 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Mon, 11 Nov 2024 17:25:09 +0900 Subject: [PATCH 04/12] cargo clippy --- token/client/src/token.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/token/client/src/token.rs b/token/client/src/token.rs index 8aaa6800941..30773f272e5 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -2321,8 +2321,8 @@ where self.get_address(), destination_account, new_decryptable_available_balance.into(), - &transfer_amount_auditor_ciphertext_lo.into(), - &transfer_amount_auditor_ciphertext_hi.into(), + &transfer_amount_auditor_ciphertext_lo, + &transfer_amount_auditor_ciphertext_hi, source_authority, &multisig_signers, equality_proof_location, @@ -2720,8 +2720,8 @@ where self.get_address(), destination_account, new_decryptable_available_balance.into(), - &transfer_amount_auditor_ciphertext_lo.into(), - &transfer_amount_auditor_ciphertext_hi.into(), + &transfer_amount_auditor_ciphertext_lo, + &transfer_amount_auditor_ciphertext_hi, source_authority, &multisig_signers, equality_proof_location, From 08e0e62846764526710be3ef916b0b781a320c9a Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Mon, 11 Nov 2024 18:22:51 +0900 Subject: [PATCH 05/12] import `elgamalciphertext_fromstr` --- .../src/extension/confidential_mint_burn/instruction.rs | 4 +++- .../src/extension/confidential_transfer/instruction.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/token/program-2022/src/extension/confidential_mint_burn/instruction.rs b/token/program-2022/src/extension/confidential_mint_burn/instruction.rs index ad268fdbecf..993add92e65 100644 --- a/token/program-2022/src/extension/confidential_mint_burn/instruction.rs +++ b/token/program-2022/src/extension/confidential_mint_burn/instruction.rs @@ -1,6 +1,8 @@ #[cfg(feature = "serde-traits")] use { - crate::serialization::{aeciphertext_fromstr, elgamalpubkey_fromstr}, + crate::serialization::{ + aeciphertext_fromstr, elgamalciphertext_fromstr, elgamalpubkey_fromstr, + }, serde::{Deserialize, Serialize}, }; use { diff --git a/token/program-2022/src/extension/confidential_transfer/instruction.rs b/token/program-2022/src/extension/confidential_transfer/instruction.rs index bd4b8c64c4f..152302df3ba 100644 --- a/token/program-2022/src/extension/confidential_transfer/instruction.rs +++ b/token/program-2022/src/extension/confidential_transfer/instruction.rs @@ -3,7 +3,7 @@ pub use solana_zk_sdk::zk_elgamal_proof_program::{ }; #[cfg(feature = "serde-traits")] use { - crate::serialization::aeciphertext_fromstr, + crate::serialization::{aeciphertext_fromstr, elgamalciphertext_fromstr}, serde::{Deserialize, Serialize}, }; use { From 99bd97b195e45b2f2918ae50be55159217cced59 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Tue, 12 Nov 2024 12:11:38 +0900 Subject: [PATCH 06/12] update token-cli --- token/cli/src/command.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/token/cli/src/command.rs b/token/cli/src/command.rs index 46cbffa9262..825059920a7 100644 --- a/token/cli/src/command.rs +++ b/token/cli/src/command.rs @@ -57,10 +57,13 @@ use { transfer_hook::TransferHook, BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned, }, - solana_zk_sdk::encryption::{ - auth_encryption::AeKey, - elgamal::{self, ElGamalKeypair}, - pod::elgamal::PodElGamalPubkey, + solana_zk_sdk::{ + encryption::{ + auth_encryption::AeKey, + elgamal::{self, ElGamalKeypair}, + pod::elgamal::PodElGamalPubkey, + }, + zk_elgamal_proof_program::proof_data::ZkProofData, }, state::{Account, AccountState, Mint}, }, @@ -1623,6 +1626,17 @@ async fn command_transfer( ) .unwrap(); + let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .unwrap(); + let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .unwrap(); + // setup proofs let create_range_proof_context_signer = &[&range_proof_context_state_account]; let create_equality_proof_context_signer = &[&equality_proof_context_state_account]; @@ -1670,6 +1684,8 @@ async fn command_transfer( Some(&ciphertext_validity_proof_context_proof_account), Some(&range_proof_context_proof_account), transfer_balance, + Some(&transfer_amount_auditor_ciphertext_lo), + Some(&transfer_amount_auditor_ciphertext_hi), Some(transfer_account_info), &args.sender_elgamal_keypair, &args.sender_aes_key, From c77a50bb31de767889d8fedc1f51e07a4bad0d00 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 14 Nov 2024 10:31:59 +0900 Subject: [PATCH 07/12] use `map_err(TokenError::from)` --- .../confidential_mint_burn/processor.rs | 16 +++++------ .../confidential_transfer/processor.rs | 28 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/token/program-2022/src/extension/confidential_mint_burn/processor.rs b/token/program-2022/src/extension/confidential_mint_burn/processor.rs index 90698a4be4c..676d6404286 100644 --- a/token/program-2022/src/extension/confidential_mint_burn/processor.rs +++ b/token/program-2022/src/extension/confidential_mint_burn/processor.rs @@ -213,11 +213,11 @@ fn process_confidential_mint( let proof_context_auditor_ciphertext_lo = proof_context .mint_amount_ciphertext_lo .try_extract_ciphertext(2) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let proof_context_auditor_ciphertext_hi = proof_context .mint_amount_ciphertext_hi .try_extract_ciphertext(2) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; check_auditor_ciphertext( &data.mint_amount_auditor_ciphertext_lo, @@ -231,7 +231,7 @@ fn process_confidential_mint( &proof_context .mint_amount_ciphertext_lo .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?, + .map_err(TokenError::from)?, ) .ok_or(TokenError::CiphertextArithmeticFailed)?; confidential_transfer_account.pending_balance_hi = ciphertext_arithmetic::add( @@ -239,7 +239,7 @@ fn process_confidential_mint( &proof_context .mint_amount_ciphertext_hi .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?, + .map_err(TokenError::from)?, ) .ok_or(TokenError::CiphertextArithmeticFailed)?; @@ -330,11 +330,11 @@ fn process_confidential_burn( let proof_context_auditor_ciphertext_lo = proof_context .burn_amount_ciphertext_lo .try_extract_ciphertext(2) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let proof_context_auditor_ciphertext_hi = proof_context .burn_amount_ciphertext_hi .try_extract_ciphertext(2) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; check_auditor_ciphertext( &data.burn_amount_auditor_ciphertext_lo, @@ -346,11 +346,11 @@ fn process_confidential_burn( let burn_amount_lo = &proof_context .burn_amount_ciphertext_lo .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let burn_amount_hi = &proof_context .burn_amount_ciphertext_hi .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let new_source_available_balance = ciphertext_arithmetic::subtract_with_lo_hi( &confidential_transfer_account.available_balance, diff --git a/token/program-2022/src/extension/confidential_transfer/processor.rs b/token/program-2022/src/extension/confidential_transfer/processor.rs index 5d437322675..1622ad1abb8 100644 --- a/token/program-2022/src/extension/confidential_transfer/processor.rs +++ b/token/program-2022/src/extension/confidential_transfer/processor.rs @@ -729,11 +729,11 @@ fn process_transfer( let proof_context_auditor_ciphertext_lo = proof_context .ciphertext_lo .try_extract_ciphertext(2) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let proof_context_auditor_ciphertext_hi = proof_context .ciphertext_hi .try_extract_ciphertext(2) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; check_auditor_ciphertext( transfer_amount_auditor_ciphertext_lo, @@ -852,11 +852,11 @@ fn process_source_for_transfer( let source_transfer_amount_lo = proof_context .ciphertext_lo .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let source_transfer_amount_hi = proof_context .ciphertext_hi .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let new_source_available_balance = ciphertext_arithmetic::subtract_with_lo_hi( &confidential_transfer_account.available_balance, @@ -914,11 +914,11 @@ fn process_destination_for_transfer( let destination_ciphertext_lo = proof_context .ciphertext_lo .try_extract_ciphertext(1) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let destination_ciphertext_hi = proof_context .ciphertext_hi .try_extract_ciphertext(1) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; destination_confidential_transfer_account.pending_balance_lo = ciphertext_arithmetic::add( &destination_confidential_transfer_account.pending_balance_lo, @@ -990,11 +990,11 @@ fn process_source_for_transfer_with_fee( let source_transfer_amount_lo = proof_context .ciphertext_lo .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let source_transfer_amount_hi = proof_context .ciphertext_hi .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let new_source_available_balance = ciphertext_arithmetic::subtract_with_lo_hi( &confidential_transfer_account.available_balance, @@ -1053,11 +1053,11 @@ fn process_destination_for_transfer_with_fee( let destination_transfer_amount_lo = proof_context .ciphertext_lo .try_extract_ciphertext(1) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let destination_transfer_amount_hi = proof_context .ciphertext_hi .try_extract_ciphertext(1) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; destination_confidential_transfer_account.pending_balance_lo = ciphertext_arithmetic::add( &destination_confidential_transfer_account.pending_balance_lo, @@ -1080,11 +1080,11 @@ fn process_destination_for_transfer_with_fee( let destination_fee_lo = proof_context .fee_ciphertext_lo .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let destination_fee_hi = proof_context .fee_ciphertext_hi .try_extract_ciphertext(0) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; // Subtract the fee amount from the destination pending balance destination_confidential_transfer_account.pending_balance_lo = @@ -1105,11 +1105,11 @@ fn process_destination_for_transfer_with_fee( let withdraw_withheld_authority_fee_lo = proof_context .fee_ciphertext_lo .try_extract_ciphertext(1) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let withdraw_withheld_authority_fee_hi = proof_context .fee_ciphertext_hi .try_extract_ciphertext(1) - .map_err(|e| -> TokenError { e.into() })?; + .map_err(TokenError::from)?; let destination_confidential_transfer_fee_amount = destination_token_account.get_extension_mut::()?; From 8fc8f9896b52c5bf12178fe9c9828c7e581d79cd Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 14 Nov 2024 13:01:16 +0900 Subject: [PATCH 08/12] add `CiphertextValidityProofWithCiphertext` type --- token/client/src/token.rs | 191 +++++++++--------- .../proof-generation/src/burn.rs | 26 ++- .../proof-generation/src/errors.rs | 2 + .../proof-generation/src/lib.rs | 17 +- .../proof-generation/src/mint.rs | 26 ++- .../proof-generation/src/transfer.rs | 28 ++- .../proof-generation/src/transfer_with_fee.rs | 30 ++- .../tests/confidential_transfer.rs | 118 +++++------ .../tests/confidential_transfer_fee.rs | 6 - .../program-2022-test/tests/transfer_hook.rs | 2 - token/program-2022/src/error.rs | 1 + 11 files changed, 253 insertions(+), 194 deletions(-) diff --git a/token/client/src/token.rs b/token/client/src/token.rs index 30773f272e5..26780b6f6aa 100644 --- a/token/client/src/token.rs +++ b/token/client/src/token.rs @@ -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 { client: Arc>, pubkey: Pubkey, /* token mint */ @@ -2198,11 +2204,9 @@ 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, - transfer_amount_auditor_ciphertext_lo: Option<&PodElGamalCiphertext>, - transfer_amount_auditor_ciphertext_hi: Option<&PodElGamalCiphertext>, account_info: Option, source_elgamal_keypair: &ElGamalKeypair, source_aes_key: &AeKey, @@ -2222,71 +2226,63 @@ 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) = ciphertext_validity_proof_data { - let transfer_amount_auditor_ciphertext_lo = proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .map_err(|_| TokenError::ProofGeneration)?; - let transfer_amount_auditor_ciphertext_hi = proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .map_err(|_| TokenError::ProofGeneration)?; + if let Some(proof_data_with_ciphertext) = ciphertext_validity_proof_data_with_ciphertext + { ( - transfer_amount_auditor_ciphertext_lo, - transfer_amount_auditor_ciphertext_hi, + proof_data_with_ciphertext.ciphertext_lo, + proof_data_with_ciphertext.ciphertext_hi, ) } else { - // the validity proof data is always generated unless - // `transfer_amount_auditor_ciphertext_lo` and - // `transfer_amount_auditor_ciphertext_hi` are `Some`, so it is - // safe to unwrap + // 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_auditor_ciphertext_lo.unwrap(), - *transfer_amount_auditor_ciphertext_hi.unwrap(), + ciphertext_validity_proof_account_with_ciphertext + .unwrap() + .ciphertext_lo, + ciphertext_validity_proof_account_with_ciphertext + .unwrap() + .ciphertext_hi, ) }; @@ -2298,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(); @@ -2557,13 +2555,13 @@ 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>, transfer_amount: u64, - transfer_amount_auditor_ciphertext_lo: Option<&PodElGamalCiphertext>, - transfer_amount_auditor_ciphertext_hi: Option<&PodElGamalCiphertext>, account_info: Option, source_elgamal_keypair: &ElGamalKeypair, source_aes_key: &AeKey, @@ -2588,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, @@ -2627,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); @@ -2641,7 +2635,7 @@ 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, @@ -2649,29 +2643,24 @@ where }; let (transfer_amount_auditor_ciphertext_lo, transfer_amount_auditor_ciphertext_hi) = - if let Some(proof_data) = transfer_amount_ciphertext_validity_proof_data { - let transfer_amount_auditor_ciphertext_lo = proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .map_err(|_| TokenError::ProofGeneration)?; - let transfer_amount_auditor_ciphertext_hi = proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .map_err(|_| TokenError::ProofGeneration)?; + if let Some(proof_data_with_ciphertext) = + transfer_amount_ciphertext_validity_proof_data_with_ciphertext + { ( - transfer_amount_auditor_ciphertext_lo, - transfer_amount_auditor_ciphertext_hi, + proof_data_with_ciphertext.ciphertext_lo, + proof_data_with_ciphertext.ciphertext_hi, ) } else { - // the validity proof data is always generated unless - // `transfer_amount_auditor_ciphertext_lo` and - // `transfer_amount_auditor_ciphertext_hi` are `Some`, so it is - // safe to unwrap + // 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_auditor_ciphertext_lo.unwrap(), - *transfer_amount_auditor_ciphertext_hi.unwrap(), + transfer_amount_ciphertext_validity_proof_account_with_ciphertext + .unwrap() + .ciphertext_lo, + transfer_amount_ciphertext_validity_proof_account_with_ciphertext + .unwrap() + .ciphertext_hi, ) }; @@ -2683,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(); diff --git a/token/confidential-transfer/proof-generation/src/burn.rs b/token/confidential-transfer/proof-generation/src/burn.rs index 9b927384ac8..a5de07519c3 100644 --- a/token/confidential-transfer/proof-generation/src/burn.rs +++ b/token/confidential-transfer/proof-generation/src/burn.rs @@ -1,7 +1,7 @@ use { crate::{ encryption::BurnAmountCiphertext, errors::TokenProofGenerationError, - try_combine_lo_hi_ciphertexts, try_split_u64, + try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext, }, solana_zk_sdk::{ encryption::{ @@ -11,7 +11,7 @@ use { }, zk_elgamal_proof_program::proof_data::{ BatchedGroupedCiphertext3HandlesValidityProofData, BatchedRangeProofU128Data, - CiphertextCommitmentEqualityProofData, + CiphertextCommitmentEqualityProofData, ZkProofData, }, }, }; @@ -25,7 +25,7 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16; /// The proof data required for a confidential burn instruction pub struct BurnProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub ciphertext_validity_proof_data: BatchedGroupedCiphertext3HandlesValidityProofData, + pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext, pub range_proof_data: BatchedRangeProofU128Data, } @@ -113,6 +113,24 @@ pub fn burn_split_proof_data( ) .map_err(TokenProofGenerationError::from)?; + let burn_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let burn_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext { + proof_data: ciphertext_validity_proof_data, + ciphertext_lo: burn_amount_auditor_ciphertext_lo, + ciphertext_hi: burn_amount_auditor_ciphertext_hi, + }; + // generate range proof data let (padding_commitment, padding_opening) = Pedersen::new(0_u64); let range_proof_data = BatchedRangeProofU128Data::new( @@ -140,7 +158,7 @@ pub fn burn_split_proof_data( Ok(BurnProofData { equality_proof_data, - ciphertext_validity_proof_data, + ciphertext_validity_proof_data_with_ciphertext, range_proof_data, }) } diff --git a/token/confidential-transfer/proof-generation/src/errors.rs b/token/confidential-transfer/proof-generation/src/errors.rs index 5cb5c14e794..9f27f6ebb42 100644 --- a/token/confidential-transfer/proof-generation/src/errors.rs +++ b/token/confidential-transfer/proof-generation/src/errors.rs @@ -10,4 +10,6 @@ pub enum TokenProofGenerationError { IllegalAmountBitLength, #[error("fee calculation failed")] FeeCalculation, + #[error("ciphertext extraction failed")] + CiphertextExtraction, } diff --git a/token/confidential-transfer/proof-generation/src/lib.rs b/token/confidential-transfer/proof-generation/src/lib.rs index f8883f31954..5bde1176f97 100644 --- a/token/confidential-transfer/proof-generation/src/lib.rs +++ b/token/confidential-transfer/proof-generation/src/lib.rs @@ -1,8 +1,12 @@ use { curve25519_dalek::scalar::Scalar, - solana_zk_sdk::encryption::{ - elgamal::ElGamalCiphertext, - pedersen::{PedersenCommitment, PedersenOpening}, + solana_zk_sdk::{ + encryption::{ + elgamal::ElGamalCiphertext, + pedersen::{PedersenCommitment, PedersenOpening}, + pod::elgamal::PodElGamalCiphertext, + }, + zk_elgamal_proof_program::proof_data::BatchedGroupedCiphertext3HandlesValidityProofData, }, }; @@ -87,3 +91,10 @@ pub fn try_combine_lo_hi_openings( let two_power = 1_u64.checked_shl(bit_length as u32)?; Some(opening_lo + opening_hi * Scalar::from(two_power)) } + +#[derive(Clone, Copy)] +pub struct CiphertextValidityProofWithCiphertext { + pub proof_data: BatchedGroupedCiphertext3HandlesValidityProofData, + pub ciphertext_lo: PodElGamalCiphertext, + pub ciphertext_hi: PodElGamalCiphertext, +} diff --git a/token/confidential-transfer/proof-generation/src/mint.rs b/token/confidential-transfer/proof-generation/src/mint.rs index 1ada01840ab..38d9e71a3ec 100644 --- a/token/confidential-transfer/proof-generation/src/mint.rs +++ b/token/confidential-transfer/proof-generation/src/mint.rs @@ -1,7 +1,7 @@ use { crate::{ encryption::MintAmountCiphertext, errors::TokenProofGenerationError, - try_combine_lo_hi_ciphertexts, try_split_u64, + try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext, }, solana_zk_sdk::{ encryption::{ @@ -11,7 +11,7 @@ use { }, zk_elgamal_proof_program::proof_data::{ BatchedGroupedCiphertext3HandlesValidityProofData, BatchedRangeProofU128Data, - CiphertextCommitmentEqualityProofData, + CiphertextCommitmentEqualityProofData, ZkProofData, }, }, }; @@ -25,7 +25,7 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16; /// The proof data required for a confidential mint instruction pub struct MintProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub ciphertext_validity_proof_data: BatchedGroupedCiphertext3HandlesValidityProofData, + pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext, pub range_proof_data: BatchedRangeProofU128Data, pub new_decryptable_supply: AeCiphertext, } @@ -109,6 +109,24 @@ pub fn mint_split_proof_data( ) .map_err(TokenProofGenerationError::from)?; + let mint_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let mint_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext { + proof_data: ciphertext_validity_proof_data, + ciphertext_lo: mint_amount_auditor_ciphertext_lo, + ciphertext_hi: mint_amount_auditor_ciphertext_hi, + }; + // generate range proof data let (padding_commitment, padding_opening) = Pedersen::new(0_u64); let range_proof_data = BatchedRangeProofU128Data::new( @@ -136,7 +154,7 @@ pub fn mint_split_proof_data( Ok(MintProofData { equality_proof_data, - ciphertext_validity_proof_data, + ciphertext_validity_proof_data_with_ciphertext, range_proof_data, new_decryptable_supply: supply_aes_key.encrypt(new_supply), }) diff --git a/token/confidential-transfer/proof-generation/src/transfer.rs b/token/confidential-transfer/proof-generation/src/transfer.rs index fbb257a4fc1..642c4422eec 100644 --- a/token/confidential-transfer/proof-generation/src/transfer.rs +++ b/token/confidential-transfer/proof-generation/src/transfer.rs @@ -1,8 +1,8 @@ use { crate::{ encryption::TransferAmountCiphertext, errors::TokenProofGenerationError, - try_combine_lo_hi_ciphertexts, try_split_u64, REMAINING_BALANCE_BIT_LENGTH, - TRANSFER_AMOUNT_HI_BITS, TRANSFER_AMOUNT_LO_BITS, + try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext, + REMAINING_BALANCE_BIT_LENGTH, TRANSFER_AMOUNT_HI_BITS, TRANSFER_AMOUNT_LO_BITS, }, solana_zk_sdk::{ encryption::{ @@ -12,7 +12,7 @@ use { }, zk_elgamal_proof_program::proof_data::{ BatchedGroupedCiphertext3HandlesValidityProofData, BatchedRangeProofU128Data, - CiphertextCommitmentEqualityProofData, + CiphertextCommitmentEqualityProofData, ZkProofData, }, }, }; @@ -25,7 +25,7 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16; /// mint is not extended for fees pub struct TransferProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub ciphertext_validity_proof_data: BatchedGroupedCiphertext3HandlesValidityProofData, + pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext, pub range_proof_data: BatchedRangeProofU128Data, } @@ -120,6 +120,24 @@ pub fn transfer_split_proof_data( ) .map_err(TokenProofGenerationError::from)?; + let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext { + proof_data: ciphertext_validity_proof_data, + ciphertext_lo: transfer_amount_auditor_ciphertext_lo, + ciphertext_hi: transfer_amount_auditor_ciphertext_hi, + }; + // generate range proof data let (padding_commitment, padding_opening) = Pedersen::new(0_u64); let range_proof_data = BatchedRangeProofU128Data::new( @@ -152,7 +170,7 @@ pub fn transfer_split_proof_data( Ok(TransferProofData { equality_proof_data, - ciphertext_validity_proof_data, + ciphertext_validity_proof_data_with_ciphertext, range_proof_data, }) } diff --git a/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs b/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs index f49e1aa00ec..c263c76e993 100644 --- a/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs +++ b/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs @@ -3,7 +3,8 @@ use { encryption::{FeeCiphertext, TransferAmountCiphertext}, errors::TokenProofGenerationError, try_combine_lo_hi_ciphertexts, try_combine_lo_hi_commitments, try_combine_lo_hi_openings, - try_split_u64, TRANSFER_AMOUNT_HI_BITS, TRANSFER_AMOUNT_LO_BITS, + try_split_u64, CiphertextValidityProofWithCiphertext, TRANSFER_AMOUNT_HI_BITS, + TRANSFER_AMOUNT_LO_BITS, }, curve25519_dalek::scalar::Scalar, solana_zk_sdk::{ @@ -16,7 +17,7 @@ use { zk_elgamal_proof_program::proof_data::{ BatchedGroupedCiphertext2HandlesValidityProofData, BatchedGroupedCiphertext3HandlesValidityProofData, BatchedRangeProofU256Data, - CiphertextCommitmentEqualityProofData, PercentageWithCapProofData, + CiphertextCommitmentEqualityProofData, PercentageWithCapProofData, ZkProofData, }, }, }; @@ -34,8 +35,8 @@ const DELTA_BIT_LENGTH: usize = 48; /// mint is extended for fees pub struct TransferWithFeeProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub transfer_amount_ciphertext_validity_proof_data: - BatchedGroupedCiphertext3HandlesValidityProofData, + pub transfer_amount_ciphertext_validity_proof_data_with_ciphertext: + CiphertextValidityProofWithCiphertext, pub percentage_with_cap_proof_data: PercentageWithCapProofData, pub fee_ciphertext_validity_proof_data: BatchedGroupedCiphertext2HandlesValidityProofData, pub range_proof_data: BatchedRangeProofU256Data, @@ -138,6 +139,25 @@ pub fn transfer_with_fee_split_proof_data( ) .map_err(TokenProofGenerationError::from)?; + let transfer_amount_auditor_ciphertext_lo = transfer_amount_ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_lo + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let transfer_amount_auditor_ciphertext_hi = transfer_amount_ciphertext_validity_proof_data + .context_data() + .grouped_ciphertext_hi + .try_extract_ciphertext(2) + .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; + + let transfer_amount_ciphertext_validity_proof_data_with_ciphertext = + CiphertextValidityProofWithCiphertext { + proof_data: transfer_amount_ciphertext_validity_proof_data, + ciphertext_lo: transfer_amount_auditor_ciphertext_lo, + ciphertext_hi: transfer_amount_auditor_ciphertext_hi, + }; + // calculate fee let transfer_fee_basis_points = fee_rate_basis_points; let transfer_fee_maximum_fee = maximum_fee; @@ -298,7 +318,7 @@ pub fn transfer_with_fee_split_proof_data( Ok(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, diff --git a/token/program-2022-test/tests/confidential_transfer.rs b/token/program-2022-test/tests/confidential_transfer.rs index d322230d572..e3c80fe6f44 100644 --- a/token/program-2022-test/tests/confidential_transfer.rs +++ b/token/program-2022-test/tests/confidential_transfer.rs @@ -37,8 +37,8 @@ use { spl_token_client::{ client::ProgramBanksClientProcessTransaction, token::{ - ExtensionInitializationParams, ProofAccount, Token, TokenError as TokenClientError, - TokenResult, + ExtensionInitializationParams, ProofAccount, ProofAccountWithCiphertext, Token, + TokenError as TokenClientError, TokenResult, }, }, spl_token_confidential_transfer_proof_extraction::instruction::{ProofData, ProofLocation}, @@ -1321,8 +1321,6 @@ async fn confidential_transfer_with_option( None, transfer_amount, None, - None, - None, source_elgamal_keypair, source_aes_key, destination_elgamal_pubkey, @@ -1340,7 +1338,7 @@ async fn confidential_transfer_with_option( 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( @@ -1352,16 +1350,10 @@ async fn confidential_transfer_with_option( ) .unwrap(); - let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .unwrap(); - let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .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; let equality_proof_record_account = Keypair::new(); let ciphertext_validity_proof_record_account = Keypair::new(); @@ -1388,7 +1380,7 @@ async fn confidential_transfer_with_option( .confidential_transfer_create_record_account( &ciphertext_validity_proof_record_account.pubkey(), &record_account_authority.pubkey(), - &ciphertext_validity_proof_data, + &ciphertext_validity_proof_data_with_ciphertext.proof_data, &ciphertext_validity_proof_record_account, &record_account_authority, ) @@ -1422,17 +1414,21 @@ async fn confidential_transfer_with_option( token }; + let ciphertext_validity_proof_account_with_ciphertext = ProofAccountWithCiphertext { + proof_account: ciphertext_validity_proof_account, + ciphertext_lo: transfer_amount_auditor_ciphertext_lo, + ciphertext_hi: transfer_amount_auditor_ciphertext_hi, + }; + let result = transfer_token .confidential_transfer_transfer( source_account, destination_account, source_authority, Some(&equality_proof_account), - Some(&ciphertext_validity_proof_account), + Some(&ciphertext_validity_proof_account_with_ciphertext), Some(&range_proof_account), transfer_amount, - Some(&transfer_amount_auditor_ciphertext_lo), - Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, @@ -1483,7 +1479,7 @@ async fn confidential_transfer_with_option( 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( @@ -1495,16 +1491,10 @@ async fn confidential_transfer_with_option( ) .unwrap(); - let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .unwrap(); - let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .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; let equality_proof_context_account = Keypair::new(); let ciphertext_validity_proof_context_account = Keypair::new(); @@ -1529,7 +1519,7 @@ async fn confidential_transfer_with_option( .confidential_transfer_create_context_state_account( &ciphertext_validity_proof_context_account.pubkey(), &context_account_authority.pubkey(), - &ciphertext_validity_proof_data, + &ciphertext_validity_proof_data_with_ciphertext.proof_data, false, &[&ciphertext_validity_proof_context_account], ) @@ -1559,17 +1549,21 @@ async fn confidential_transfer_with_option( token }; + 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 result = transfer_token .confidential_transfer_transfer( source_account, destination_account, source_authority, 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_amount, - Some(&transfer_amount_auditor_ciphertext_lo), - Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, @@ -1900,8 +1894,6 @@ async fn confidential_transfer_with_fee_with_option( None, transfer_amount, None, - None, - None, source_elgamal_keypair, source_aes_key, destination_elgamal_pubkey, @@ -1922,7 +1914,7 @@ async fn confidential_transfer_with_fee_with_option( 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, @@ -1940,17 +1932,9 @@ async fn confidential_transfer_with_fee_with_option( .unwrap(); let transfer_amount_auditor_ciphertext_lo = - transfer_amount_ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .unwrap(); + transfer_amount_ciphertext_validity_proof_data_with_ciphertext.ciphertext_lo; let transfer_amount_auditor_ciphertext_hi = - transfer_amount_ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .unwrap(); + transfer_amount_ciphertext_validity_proof_data_with_ciphertext.ciphertext_hi; let equality_proof_record_account = Keypair::new(); let transfer_amount_ciphertext_validity_proof_record_account = Keypair::new(); @@ -1979,7 +1963,7 @@ async fn confidential_transfer_with_fee_with_option( .confidential_transfer_create_record_account( &transfer_amount_ciphertext_validity_proof_record_account.pubkey(), &record_account_authority.pubkey(), - &transfer_amount_ciphertext_validity_proof_data, + &transfer_amount_ciphertext_validity_proof_data_with_ciphertext.proof_data, &transfer_amount_ciphertext_validity_proof_record_account, &record_account_authority, ) @@ -2045,19 +2029,24 @@ async fn confidential_transfer_with_fee_with_option( token }; + let transfer_amount_ciphertext_validity_proof_account_with_ciphertext = + ProofAccountWithCiphertext { + proof_account: transfer_amount_ciphertext_validity_proof_account, + ciphertext_lo: transfer_amount_auditor_ciphertext_lo, + ciphertext_hi: transfer_amount_auditor_ciphertext_hi, + }; + let result = transfer_token .confidential_transfer_transfer_with_fee( source_account, destination_account, source_authority, Some(&equality_proof_account), - Some(&transfer_amount_ciphertext_validity_proof_account), + Some(&transfer_amount_ciphertext_validity_proof_account_with_ciphertext), Some(&fee_sigma_proof_account), Some(&fee_ciphertext_validity_proof_account), Some(&range_proof_account), transfer_amount, - Some(&transfer_amount_auditor_ciphertext_lo), - Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, @@ -2131,7 +2120,7 @@ async fn confidential_transfer_with_fee_with_option( 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, @@ -2149,17 +2138,9 @@ async fn confidential_transfer_with_fee_with_option( .unwrap(); let transfer_amount_auditor_ciphertext_lo = - transfer_amount_ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .unwrap(); + transfer_amount_ciphertext_validity_proof_data_with_ciphertext.ciphertext_lo; let transfer_amount_auditor_ciphertext_hi = - transfer_amount_ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .unwrap(); + transfer_amount_ciphertext_validity_proof_data_with_ciphertext.ciphertext_hi; let equality_proof_context_account = Keypair::new(); let transfer_amount_ciphertext_validity_proof_context_account = Keypair::new(); @@ -2186,7 +2167,7 @@ async fn confidential_transfer_with_fee_with_option( .confidential_transfer_create_context_state_account( &transfer_amount_ciphertext_validity_proof_context_account.pubkey(), &context_account_authority.pubkey(), - &transfer_amount_ciphertext_validity_proof_data, + &transfer_amount_ciphertext_validity_proof_data_with_ciphertext.proof_data, false, &[&transfer_amount_ciphertext_validity_proof_context_account], ) @@ -2247,19 +2228,24 @@ async fn confidential_transfer_with_fee_with_option( token }; + let transfer_amount_ciphertext_validity_proof_account_with_ciphertext = + ProofAccountWithCiphertext { + proof_account: transfer_amount_ciphertext_validity_proof_context_proof_account, + ciphertext_lo: transfer_amount_auditor_ciphertext_lo, + ciphertext_hi: transfer_amount_auditor_ciphertext_hi, + }; + let result = transfer_token .confidential_transfer_transfer_with_fee( source_account, destination_account, source_authority, Some(&equality_proof_context_proof_account), - Some(&transfer_amount_ciphertext_validity_proof_context_proof_account), + Some(&transfer_amount_ciphertext_validity_proof_account_with_ciphertext), Some(&fee_sigma_proof_context_proof_account), Some(&fee_ciphertext_validity_proof_context_proof_account), Some(&range_proof_context_proof_account), transfer_amount, - Some(&transfer_amount_auditor_ciphertext_lo), - Some(&transfer_amount_auditor_ciphertext_hi), None, source_elgamal_keypair, source_aes_key, diff --git a/token/program-2022-test/tests/confidential_transfer_fee.rs b/token/program-2022-test/tests/confidential_transfer_fee.rs index 4e5f636273a..c2664525c5f 100644 --- a/token/program-2022-test/tests/confidential_transfer_fee.rs +++ b/token/program-2022-test/tests/confidential_transfer_fee.rs @@ -690,8 +690,6 @@ async fn confidential_transfer_withdraw_withheld_tokens_from_mint_with_option( None, 100, None, - None, - None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), @@ -1018,8 +1016,6 @@ async fn confidential_transfer_withdraw_withheld_tokens_from_accounts_with_optio None, 100, None, - None, - None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), @@ -1159,8 +1155,6 @@ async fn confidential_transfer_harvest_withheld_tokens_to_mint() { None, 100, None, - None, - None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), diff --git a/token/program-2022-test/tests/transfer_hook.rs b/token/program-2022-test/tests/transfer_hook.rs index 30c247bb545..32f929857a4 100644 --- a/token/program-2022-test/tests/transfer_hook.rs +++ b/token/program-2022-test/tests/transfer_hook.rs @@ -1004,8 +1004,6 @@ async fn success_confidential_transfer() { None, amount, None, - None, - None, &alice_meta.elgamal_keypair, &alice_meta.aes_key, bob_meta.elgamal_keypair.pubkey(), diff --git a/token/program-2022/src/error.rs b/token/program-2022/src/error.rs index 54e4e250190..832ccf65715 100644 --- a/token/program-2022/src/error.rs +++ b/token/program-2022/src/error.rs @@ -465,6 +465,7 @@ impl From for TokenError { TokenProofGenerationError::NotEnoughFunds => TokenError::InsufficientFunds, TokenProofGenerationError::IllegalAmountBitLength => TokenError::IllegalBitLength, TokenProofGenerationError::FeeCalculation => TokenError::FeeCalculation, + TokenProofGenerationError::CiphertextExtraction => TokenError::MalformedCiphertext, } } } From afb9652bdb90b6e7f44d2c1d360e76748df72142 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 14 Nov 2024 16:07:35 +0900 Subject: [PATCH 09/12] update token-cli using the updated syntax --- token/cli/src/command.rs | 44 +++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/token/cli/src/command.rs b/token/cli/src/command.rs index 825059920a7..8a7cf30b5dd 100644 --- a/token/cli/src/command.rs +++ b/token/cli/src/command.rs @@ -57,19 +57,19 @@ use { transfer_hook::TransferHook, BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned, }, - solana_zk_sdk::{ - encryption::{ - auth_encryption::AeKey, - elgamal::{self, ElGamalKeypair}, - pod::elgamal::PodElGamalPubkey, - }, - zk_elgamal_proof_program::proof_data::ZkProofData, + solana_zk_sdk::encryption::{ + auth_encryption::AeKey, + elgamal::{self, ElGamalKeypair}, + pod::elgamal::PodElGamalPubkey, }, state::{Account, AccountState, Mint}, }, 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, @@ -1614,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( @@ -1626,16 +1626,10 @@ async fn command_transfer( ) .unwrap(); - let transfer_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_lo - .try_extract_ciphertext(2) - .unwrap(); - let transfer_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data - .context_data() - .grouped_ciphertext_hi - .try_extract_ciphertext(2) - .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]; @@ -1661,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 ) @@ -1675,17 +1669,21 @@ 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_amount_auditor_ciphertext_lo), - Some(&transfer_amount_auditor_ciphertext_hi), Some(transfer_account_info), &args.sender_elgamal_keypair, &args.sender_aes_key, From 84c37be1b8d0c5d2bfe97f5f0c2d031117139aff Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 14 Nov 2024 16:17:27 +0900 Subject: [PATCH 10/12] add comments describing the type `CiphertextValidityProofWithCiphertext` --- token/confidential-transfer/proof-generation/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/token/confidential-transfer/proof-generation/src/lib.rs b/token/confidential-transfer/proof-generation/src/lib.rs index 5bde1176f97..2cd42bc2d26 100644 --- a/token/confidential-transfer/proof-generation/src/lib.rs +++ b/token/confidential-transfer/proof-generation/src/lib.rs @@ -92,6 +92,15 @@ pub fn try_combine_lo_hi_openings( Some(opening_lo + opening_hi * Scalar::from(two_power)) } +/// A type that wraps a ciphertext validity proof along with two `lo` and `hi` +/// ciphertexts. +/// +/// Ciphertext validity proof data contains grouped ElGamal ciphertexts (`lo` +/// and `hi`) and a proof containing the +/// validity of these ciphertexts. Token client-side logic often requires a +/// function to extract specific forms of the grouped ElGamal ciphertexts. This +/// type is a convenience type that contains the proof data and the extracted +/// ciphertexts. #[derive(Clone, Copy)] pub struct CiphertextValidityProofWithCiphertext { pub proof_data: BatchedGroupedCiphertext3HandlesValidityProofData, From 3ccab777fb7529824beb79356c73ba3b8ee3e7b5 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 14 Nov 2024 20:22:20 +0900 Subject: [PATCH 11/12] update proof tests --- .../proof-tests/tests/proof_test.rs | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/token/confidential-transfer/proof-tests/tests/proof_test.rs b/token/confidential-transfer/proof-tests/tests/proof_test.rs index 6e73e303ed3..d5e0110e0af 100644 --- a/token/confidential-transfer/proof-tests/tests/proof_test.rs +++ b/token/confidential-transfer/proof-tests/tests/proof_test.rs @@ -42,7 +42,7 @@ fn test_transfer_proof_validity(spendable_balance: u64, transfer_amount: u64) { let TransferProofData { equality_proof_data, - ciphertext_validity_proof_data, + ciphertext_validity_proof_data_with_ciphertext, range_proof_data, } = transfer_split_proof_data( &spendable_ciphertext, @@ -56,12 +56,17 @@ fn test_transfer_proof_validity(spendable_balance: u64, transfer_amount: u64) { .unwrap(); equality_proof_data.verify_proof().unwrap(); - ciphertext_validity_proof_data.verify_proof().unwrap(); + ciphertext_validity_proof_data_with_ciphertext + .proof_data + .verify_proof() + .unwrap(); range_proof_data.verify_proof().unwrap(); TransferProofContext::verify_and_extract( equality_proof_data.context_data(), - ciphertext_validity_proof_data.context_data(), + ciphertext_validity_proof_data_with_ciphertext + .proof_data + .context_data(), range_proof_data.context_data(), ) .unwrap(); @@ -112,7 +117,7 @@ fn test_transfer_with_fee_proof_validity( 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, @@ -131,7 +136,8 @@ fn test_transfer_with_fee_proof_validity( .unwrap(); equality_proof_data.verify_proof().unwrap(); - transfer_amount_ciphertext_validity_proof_data + transfer_amount_ciphertext_validity_proof_data_with_ciphertext + .proof_data .verify_proof() .unwrap(); percentage_with_cap_proof_data.verify_proof().unwrap(); @@ -140,7 +146,9 @@ fn test_transfer_with_fee_proof_validity( TransferWithFeeProofContext::verify_and_extract( equality_proof_data.context_data(), - transfer_amount_ciphertext_validity_proof_data.context_data(), + transfer_amount_ciphertext_validity_proof_data_with_ciphertext + .proof_data + .context_data(), percentage_with_cap_proof_data.context_data(), fee_ciphertext_validity_proof_data.context_data(), range_proof_data.context_data(), @@ -220,7 +228,7 @@ fn test_mint_validity(mint_amount: u64, supply: u64) { let MintProofData { equality_proof_data, - ciphertext_validity_proof_data, + ciphertext_validity_proof_data_with_ciphertext, range_proof_data, new_decryptable_supply: _, } = mint_split_proof_data( @@ -235,12 +243,17 @@ fn test_mint_validity(mint_amount: u64, supply: u64) { .unwrap(); equality_proof_data.verify_proof().unwrap(); - ciphertext_validity_proof_data.verify_proof().unwrap(); + ciphertext_validity_proof_data_with_ciphertext + .proof_data + .verify_proof() + .unwrap(); range_proof_data.verify_proof().unwrap(); MintProofContext::verify_and_extract( equality_proof_data.context_data(), - ciphertext_validity_proof_data.context_data(), + ciphertext_validity_proof_data_with_ciphertext + .proof_data + .context_data(), range_proof_data.context_data(), ) .unwrap(); @@ -270,7 +283,7 @@ fn test_burn_validity(spendable_balance: u64, burn_amount: u64) { let BurnProofData { equality_proof_data, - ciphertext_validity_proof_data, + ciphertext_validity_proof_data_with_ciphertext, range_proof_data, } = burn_split_proof_data( &spendable_balance_ciphertext, @@ -284,12 +297,17 @@ fn test_burn_validity(spendable_balance: u64, burn_amount: u64) { .unwrap(); equality_proof_data.verify_proof().unwrap(); - ciphertext_validity_proof_data.verify_proof().unwrap(); + ciphertext_validity_proof_data_with_ciphertext + .proof_data + .verify_proof() + .unwrap(); range_proof_data.verify_proof().unwrap(); BurnProofContext::verify_and_extract( equality_proof_data.context_data(), - ciphertext_validity_proof_data.context_data(), + ciphertext_validity_proof_data_with_ciphertext + .proof_data + .context_data(), range_proof_data.context_data(), ) .unwrap(); From 2bfa85174554376432f7c4ab0c142b5fde0f3fe4 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Fri, 15 Nov 2024 09:19:09 +0900 Subject: [PATCH 12/12] update to `CiphertextValidityProofWithAuditorCiphertext` --- .../proof-generation/src/burn.rs | 16 +++++++++------- .../proof-generation/src/lib.rs | 11 +++++------ .../proof-generation/src/mint.rs | 16 +++++++++------- .../proof-generation/src/transfer.rs | 16 +++++++++------- .../proof-generation/src/transfer_with_fee.rs | 6 +++--- 5 files changed, 35 insertions(+), 30 deletions(-) diff --git a/token/confidential-transfer/proof-generation/src/burn.rs b/token/confidential-transfer/proof-generation/src/burn.rs index a5de07519c3..ae127d9e9a6 100644 --- a/token/confidential-transfer/proof-generation/src/burn.rs +++ b/token/confidential-transfer/proof-generation/src/burn.rs @@ -1,7 +1,7 @@ use { crate::{ encryption::BurnAmountCiphertext, errors::TokenProofGenerationError, - try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext, + try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithAuditorCiphertext, }, solana_zk_sdk::{ encryption::{ @@ -25,7 +25,8 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16; /// The proof data required for a confidential burn instruction pub struct BurnProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext, + pub ciphertext_validity_proof_data_with_ciphertext: + CiphertextValidityProofWithAuditorCiphertext, pub range_proof_data: BatchedRangeProofU128Data, } @@ -125,11 +126,12 @@ pub fn burn_split_proof_data( .try_extract_ciphertext(2) .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; - let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext { - proof_data: ciphertext_validity_proof_data, - ciphertext_lo: burn_amount_auditor_ciphertext_lo, - ciphertext_hi: burn_amount_auditor_ciphertext_hi, - }; + let ciphertext_validity_proof_data_with_ciphertext = + CiphertextValidityProofWithAuditorCiphertext { + proof_data: ciphertext_validity_proof_data, + ciphertext_lo: burn_amount_auditor_ciphertext_lo, + ciphertext_hi: burn_amount_auditor_ciphertext_hi, + }; // generate range proof data let (padding_commitment, padding_opening) = Pedersen::new(0_u64); diff --git a/token/confidential-transfer/proof-generation/src/lib.rs b/token/confidential-transfer/proof-generation/src/lib.rs index 2cd42bc2d26..39a2db74da4 100644 --- a/token/confidential-transfer/proof-generation/src/lib.rs +++ b/token/confidential-transfer/proof-generation/src/lib.rs @@ -96,13 +96,12 @@ pub fn try_combine_lo_hi_openings( /// ciphertexts. /// /// Ciphertext validity proof data contains grouped ElGamal ciphertexts (`lo` -/// and `hi`) and a proof containing the -/// validity of these ciphertexts. Token client-side logic often requires a -/// function to extract specific forms of the grouped ElGamal ciphertexts. This -/// type is a convenience type that contains the proof data and the extracted -/// ciphertexts. +/// and `hi`) and a proof containing the validity of these ciphertexts. Token +/// client-side logic often requires a function to extract specific forms of +/// the grouped ElGamal ciphertexts. This type is a convenience type that +/// contains the proof data and the extracted ciphertexts. #[derive(Clone, Copy)] -pub struct CiphertextValidityProofWithCiphertext { +pub struct CiphertextValidityProofWithAuditorCiphertext { pub proof_data: BatchedGroupedCiphertext3HandlesValidityProofData, pub ciphertext_lo: PodElGamalCiphertext, pub ciphertext_hi: PodElGamalCiphertext, diff --git a/token/confidential-transfer/proof-generation/src/mint.rs b/token/confidential-transfer/proof-generation/src/mint.rs index 38d9e71a3ec..1f06a1c0156 100644 --- a/token/confidential-transfer/proof-generation/src/mint.rs +++ b/token/confidential-transfer/proof-generation/src/mint.rs @@ -1,7 +1,7 @@ use { crate::{ encryption::MintAmountCiphertext, errors::TokenProofGenerationError, - try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext, + try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithAuditorCiphertext, }, solana_zk_sdk::{ encryption::{ @@ -25,7 +25,8 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16; /// The proof data required for a confidential mint instruction pub struct MintProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext, + pub ciphertext_validity_proof_data_with_ciphertext: + CiphertextValidityProofWithAuditorCiphertext, pub range_proof_data: BatchedRangeProofU128Data, pub new_decryptable_supply: AeCiphertext, } @@ -121,11 +122,12 @@ pub fn mint_split_proof_data( .try_extract_ciphertext(2) .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; - let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext { - proof_data: ciphertext_validity_proof_data, - ciphertext_lo: mint_amount_auditor_ciphertext_lo, - ciphertext_hi: mint_amount_auditor_ciphertext_hi, - }; + let ciphertext_validity_proof_data_with_ciphertext = + CiphertextValidityProofWithAuditorCiphertext { + proof_data: ciphertext_validity_proof_data, + ciphertext_lo: mint_amount_auditor_ciphertext_lo, + ciphertext_hi: mint_amount_auditor_ciphertext_hi, + }; // generate range proof data let (padding_commitment, padding_opening) = Pedersen::new(0_u64); diff --git a/token/confidential-transfer/proof-generation/src/transfer.rs b/token/confidential-transfer/proof-generation/src/transfer.rs index 642c4422eec..4d59cc95f4d 100644 --- a/token/confidential-transfer/proof-generation/src/transfer.rs +++ b/token/confidential-transfer/proof-generation/src/transfer.rs @@ -1,7 +1,7 @@ use { crate::{ encryption::TransferAmountCiphertext, errors::TokenProofGenerationError, - try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithCiphertext, + try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithAuditorCiphertext, REMAINING_BALANCE_BIT_LENGTH, TRANSFER_AMOUNT_HI_BITS, TRANSFER_AMOUNT_LO_BITS, }, solana_zk_sdk::{ @@ -25,7 +25,8 @@ const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16; /// mint is not extended for fees pub struct TransferProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, - pub ciphertext_validity_proof_data_with_ciphertext: CiphertextValidityProofWithCiphertext, + pub ciphertext_validity_proof_data_with_ciphertext: + CiphertextValidityProofWithAuditorCiphertext, pub range_proof_data: BatchedRangeProofU128Data, } @@ -132,11 +133,12 @@ pub fn transfer_split_proof_data( .try_extract_ciphertext(2) .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; - let ciphertext_validity_proof_data_with_ciphertext = CiphertextValidityProofWithCiphertext { - proof_data: ciphertext_validity_proof_data, - ciphertext_lo: transfer_amount_auditor_ciphertext_lo, - ciphertext_hi: transfer_amount_auditor_ciphertext_hi, - }; + let ciphertext_validity_proof_data_with_ciphertext = + CiphertextValidityProofWithAuditorCiphertext { + proof_data: ciphertext_validity_proof_data, + ciphertext_lo: transfer_amount_auditor_ciphertext_lo, + ciphertext_hi: transfer_amount_auditor_ciphertext_hi, + }; // generate range proof data let (padding_commitment, padding_opening) = Pedersen::new(0_u64); diff --git a/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs b/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs index c263c76e993..5e5939f6184 100644 --- a/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs +++ b/token/confidential-transfer/proof-generation/src/transfer_with_fee.rs @@ -3,7 +3,7 @@ use { encryption::{FeeCiphertext, TransferAmountCiphertext}, errors::TokenProofGenerationError, try_combine_lo_hi_ciphertexts, try_combine_lo_hi_commitments, try_combine_lo_hi_openings, - try_split_u64, CiphertextValidityProofWithCiphertext, TRANSFER_AMOUNT_HI_BITS, + try_split_u64, CiphertextValidityProofWithAuditorCiphertext, TRANSFER_AMOUNT_HI_BITS, TRANSFER_AMOUNT_LO_BITS, }, curve25519_dalek::scalar::Scalar, @@ -36,7 +36,7 @@ const DELTA_BIT_LENGTH: usize = 48; pub struct TransferWithFeeProofData { pub equality_proof_data: CiphertextCommitmentEqualityProofData, pub transfer_amount_ciphertext_validity_proof_data_with_ciphertext: - CiphertextValidityProofWithCiphertext, + CiphertextValidityProofWithAuditorCiphertext, pub percentage_with_cap_proof_data: PercentageWithCapProofData, pub fee_ciphertext_validity_proof_data: BatchedGroupedCiphertext2HandlesValidityProofData, pub range_proof_data: BatchedRangeProofU256Data, @@ -152,7 +152,7 @@ pub fn transfer_with_fee_split_proof_data( .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?; let transfer_amount_ciphertext_validity_proof_data_with_ciphertext = - CiphertextValidityProofWithCiphertext { + CiphertextValidityProofWithAuditorCiphertext { proof_data: transfer_amount_ciphertext_validity_proof_data, ciphertext_lo: transfer_amount_auditor_ciphertext_lo, ciphertext_hi: transfer_amount_auditor_ciphertext_hi,