spl_token_confidential_transfer_proof_extraction/
transfer.rsuse {
crate::{encryption::PodTransferAmountCiphertext, errors::TokenProofExtractionError},
solana_zk_sdk::{
encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
zk_elgamal_proof_program::proof_data::{
BatchedGroupedCiphertext3HandlesValidityProofContext, BatchedRangeProofContext,
CiphertextCommitmentEqualityProofContext,
},
},
};
pub struct TransferPubkeys {
pub source: PodElGamalPubkey,
pub destination: PodElGamalPubkey,
pub auditor: PodElGamalPubkey,
}
pub struct TransferProofContext {
pub ciphertext_lo: PodTransferAmountCiphertext,
pub ciphertext_hi: PodTransferAmountCiphertext,
pub transfer_pubkeys: TransferPubkeys,
pub new_source_ciphertext: PodElGamalCiphertext,
}
impl TransferProofContext {
pub fn verify_and_extract(
equality_proof_context: &CiphertextCommitmentEqualityProofContext,
ciphertext_validity_proof_context: &BatchedGroupedCiphertext3HandlesValidityProofContext,
range_proof_context: &BatchedRangeProofContext,
) -> Result<Self, TokenProofExtractionError> {
let CiphertextCommitmentEqualityProofContext {
pubkey: source_pubkey_from_equality_proof,
ciphertext: new_source_ciphertext,
commitment: new_source_commitment,
} = equality_proof_context;
let BatchedGroupedCiphertext3HandlesValidityProofContext {
first_pubkey: source_pubkey_from_validity_proof,
second_pubkey: destination_pubkey,
third_pubkey: auditor_pubkey,
grouped_ciphertext_lo: transfer_amount_ciphertext_lo,
grouped_ciphertext_hi: transfer_amount_ciphertext_hi,
} = ciphertext_validity_proof_context;
let BatchedRangeProofContext {
commitments: range_proof_commitments,
bit_lengths: range_proof_bit_lengths,
} = range_proof_context;
if source_pubkey_from_equality_proof != source_pubkey_from_validity_proof {
return Err(TokenProofExtractionError::ElGamalPubkeyMismatch);
}
let transfer_amount_commitment_lo = transfer_amount_ciphertext_lo.extract_commitment();
let transfer_amount_commitment_hi = transfer_amount_ciphertext_hi.extract_commitment();
let expected_commitments = [
*new_source_commitment,
transfer_amount_commitment_lo,
transfer_amount_commitment_hi,
];
if !range_proof_commitments
.iter()
.zip(expected_commitments.iter())
.all(|(proof_commitment, expected_commitment)| proof_commitment == expected_commitment)
{
return Err(TokenProofExtractionError::PedersenCommitmentMismatch);
}
const REMAINING_BALANCE_BIT_LENGTH: u8 = 64;
const TRANSFER_AMOUNT_LO_BIT_LENGTH: u8 = 16;
const TRANSFER_AMOUNT_HI_BIT_LENGTH: u8 = 32;
const PADDING_BIT_LENGTH: u8 = 16;
let expected_bit_lengths = [
REMAINING_BALANCE_BIT_LENGTH,
TRANSFER_AMOUNT_LO_BIT_LENGTH,
TRANSFER_AMOUNT_HI_BIT_LENGTH,
PADDING_BIT_LENGTH,
]
.iter();
if !range_proof_bit_lengths
.iter()
.zip(expected_bit_lengths)
.all(|(proof_len, expected_len)| proof_len == expected_len)
{
return Err(TokenProofExtractionError::RangeProofLengthMismatch);
}
let transfer_pubkeys = TransferPubkeys {
source: *source_pubkey_from_equality_proof,
destination: *destination_pubkey,
auditor: *auditor_pubkey,
};
let context_info = TransferProofContext {
ciphertext_lo: PodTransferAmountCiphertext(*transfer_amount_ciphertext_lo),
ciphertext_hi: PodTransferAmountCiphertext(*transfer_amount_ciphertext_hi),
transfer_pubkeys,
new_source_ciphertext: *new_source_ciphertext,
};
Ok(context_info)
}
}