From d21e7edd2b70bdfb1ae1a3b2a5e5b4311b25bcdf Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Thu, 7 Dec 2023 06:46:57 +0900 Subject: [PATCH] [zk-token-sdk] Fix transfer with fee edge case error (#34314) --- .../src/instruction/transfer/with_fee.rs | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/zk-token-sdk/src/instruction/transfer/with_fee.rs b/zk-token-sdk/src/instruction/transfer/with_fee.rs index a0cc7ae74..4bc9a1543 100644 --- a/zk-token-sdk/src/instruction/transfer/with_fee.rs +++ b/zk-token-sdk/src/instruction/transfer/with_fee.rs @@ -41,6 +41,8 @@ use { const MAX_FEE_BASIS_POINTS: u64 = 10_000; #[cfg(not(target_os = "solana"))] const ONE_IN_BASIS_POINTS: u128 = MAX_FEE_BASIS_POINTS as u128; +#[cfg(not(target_os = "solana"))] +const MAX_DELTA_RANGE: u64 = MAX_FEE_BASIS_POINTS - 1; #[cfg(not(target_os = "solana"))] const TRANSFER_SOURCE_AMOUNT_BITS: usize = 64; @@ -51,7 +53,7 @@ const TRANSFER_AMOUNT_LO_NEGATED_BITS: usize = 16; #[cfg(not(target_os = "solana"))] const TRANSFER_AMOUNT_HI_BITS: usize = 32; #[cfg(not(target_os = "solana"))] -const TRANSFER_DELTA_BITS: usize = 48; +const TRANSFER_DELTA_BITS: usize = 16; #[cfg(not(target_os = "solana"))] const FEE_AMOUNT_LO_BITS: usize = 16; #[cfg(not(target_os = "solana"))] @@ -62,6 +64,7 @@ lazy_static::lazy_static! { pub static ref COMMITMENT_MAX: PedersenCommitment = Pedersen::encode((1_u64 << TRANSFER_AMOUNT_LO_NEGATED_BITS) - 1); pub static ref COMMITMENT_MAX_FEE_BASIS_POINTS: PedersenCommitment = Pedersen::encode(MAX_FEE_BASIS_POINTS); + pub static ref COMMITMENT_MAX_DELTA_RANGE: PedersenCommitment = Pedersen::encode(MAX_DELTA_RANGE); } /// The instruction data that is needed for the `ProofInstruction::TransferWithFee` instruction. @@ -557,24 +560,41 @@ impl TransferWithFeeProof { // generate the range proof let opening_claimed_negated = &PedersenOpening::default() - &opening_claimed; + + let combined_amount = combine_lo_hi_u64( + transfer_amount_lo, + transfer_amount_hi, + TRANSFER_AMOUNT_LO_BITS, + ); + let amount_sub_fee = combined_amount + .checked_sub(combined_fee_amount) + .ok_or(ProofGenerationError::FeeCalculation)?; + let amount_sub_fee_opening = combined_opening - combined_fee_opening; + + let delta_negated = MAX_DELTA_RANGE + .checked_sub(delta_fee) + .ok_or(ProofGenerationError::FeeCalculation)?; + let range_proof = RangeProof::new( vec![ source_new_balance, transfer_amount_lo, transfer_amount_hi, delta_fee, - MAX_FEE_BASIS_POINTS - delta_fee, + delta_negated, fee_amount_lo, fee_amount_hi, + amount_sub_fee, ], vec![ TRANSFER_SOURCE_AMOUNT_BITS, // 64 TRANSFER_AMOUNT_LO_BITS, // 16 TRANSFER_AMOUNT_HI_BITS, // 32 - TRANSFER_DELTA_BITS, // 48 - TRANSFER_DELTA_BITS, // 48 + TRANSFER_DELTA_BITS, // 16 + TRANSFER_DELTA_BITS, // 16 FEE_AMOUNT_LO_BITS, // 16 FEE_AMOUNT_HI_BITS, // 32 + TRANSFER_SOURCE_AMOUNT_BITS, // 64 ], vec![ &opening_source, @@ -584,6 +604,7 @@ impl TransferWithFeeProof { &opening_claimed_negated, opening_fee_lo, opening_fee_hi, + &amount_sub_fee_opening, ], transcript, )?; @@ -708,7 +729,8 @@ impl TransferWithFeeProof { // verify range proof let new_source_commitment = self.new_source_commitment.try_into()?; - let claimed_commitment_negated = &(*COMMITMENT_MAX_FEE_BASIS_POINTS) - &claimed_commitment; + let claimed_commitment_negated = &(*COMMITMENT_MAX_DELTA_RANGE) - &claimed_commitment; + let amount_sub_fee_commitment = combined_commitment - combined_fee_commitment; range_proof.verify( vec![ @@ -719,15 +741,17 @@ impl TransferWithFeeProof { &claimed_commitment_negated, fee_ciphertext_lo.get_commitment(), fee_ciphertext_hi.get_commitment(), + &amount_sub_fee_commitment, ], vec![ TRANSFER_SOURCE_AMOUNT_BITS, // 64 TRANSFER_AMOUNT_LO_BITS, // 16 TRANSFER_AMOUNT_HI_BITS, // 32 - TRANSFER_DELTA_BITS, // 48 - TRANSFER_DELTA_BITS, // 48 + TRANSFER_DELTA_BITS, // 16 + TRANSFER_DELTA_BITS, // 16 FEE_AMOUNT_LO_BITS, // 16 FEE_AMOUNT_HI_BITS, // 32 + TRANSFER_SOURCE_AMOUNT_BITS, // 64 ], transcript, )?;