spl_token_confidential_transfer_proof_extraction/
withdraw.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use {
    crate::errors::TokenProofExtractionError,
    solana_zk_sdk::{
        encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
        zk_elgamal_proof_program::proof_data::{
            BatchedRangeProofContext, CiphertextCommitmentEqualityProofContext,
        },
    },
};

const REMAINING_BALANCE_BIT_LENGTH: u8 = 64;

pub struct WithdrawProofContext {
    pub source_pubkey: PodElGamalPubkey,
    pub remaining_balance_ciphertext: PodElGamalCiphertext,
}

impl WithdrawProofContext {
    pub fn verify_and_extract(
        equality_proof_context: &CiphertextCommitmentEqualityProofContext,
        range_proof_context: &BatchedRangeProofContext,
    ) -> Result<Self, TokenProofExtractionError> {
        let CiphertextCommitmentEqualityProofContext {
            pubkey: source_pubkey,
            ciphertext: remaining_balance_ciphertext,
            commitment: remaining_balance_commitment,
        } = equality_proof_context;

        let BatchedRangeProofContext {
            commitments: range_proof_commitments,
            bit_lengths: range_proof_bit_lengths,
        } = range_proof_context;

        if range_proof_commitments.is_empty()
            || range_proof_commitments[0] != *remaining_balance_commitment
        {
            return Err(TokenProofExtractionError::PedersenCommitmentMismatch);
        }

        if range_proof_bit_lengths.is_empty()
            || range_proof_bit_lengths[0] != REMAINING_BALANCE_BIT_LENGTH
        {
            return Err(TokenProofExtractionError::RangeProofLengthMismatch);
        }

        let context_info = WithdrawProofContext {
            source_pubkey: *source_pubkey,
            remaining_balance_ciphertext: *remaining_balance_ciphertext,
        };

        Ok(context_info)
    }
}