spl_token_confidential_transfer_proof_extraction/
withdraw.rs

1use {
2    crate::errors::TokenProofExtractionError,
3    solana_zk_sdk::{
4        encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
5        zk_elgamal_proof_program::proof_data::{
6            BatchedRangeProofContext, CiphertextCommitmentEqualityProofContext,
7        },
8    },
9};
10
11const REMAINING_BALANCE_BIT_LENGTH: u8 = 64;
12
13pub struct WithdrawProofContext {
14    pub source_pubkey: PodElGamalPubkey,
15    pub remaining_balance_ciphertext: PodElGamalCiphertext,
16}
17
18impl WithdrawProofContext {
19    pub fn verify_and_extract(
20        equality_proof_context: &CiphertextCommitmentEqualityProofContext,
21        range_proof_context: &BatchedRangeProofContext,
22    ) -> Result<Self, TokenProofExtractionError> {
23        let CiphertextCommitmentEqualityProofContext {
24            pubkey: source_pubkey,
25            ciphertext: remaining_balance_ciphertext,
26            commitment: remaining_balance_commitment,
27        } = equality_proof_context;
28
29        let BatchedRangeProofContext {
30            commitments: range_proof_commitments,
31            bit_lengths: range_proof_bit_lengths,
32        } = range_proof_context;
33
34        // range proof context always contains 8 commitments and therefore,
35        // we can assume that `range_proof_commitments` is not empty
36        if range_proof_commitments[0] != *remaining_balance_commitment {
37            return Err(TokenProofExtractionError::PedersenCommitmentMismatch);
38        }
39
40        // range proof context always contains 8 bit lengths and therefore,
41        // we can assume that `range_proof_bit_lengths` is not empty
42        if range_proof_bit_lengths[0] != REMAINING_BALANCE_BIT_LENGTH {
43            return Err(TokenProofExtractionError::RangeProofLengthMismatch);
44        }
45
46        let context_info = WithdrawProofContext {
47            source_pubkey: *source_pubkey,
48            remaining_balance_ciphertext: *remaining_balance_ciphertext,
49        };
50
51        Ok(context_info)
52    }
53}