spl_token_confidential_transfer_proof_extraction/
mint.rs1use {
2 crate::{encryption::PodMintAmountCiphertext, errors::TokenProofExtractionError},
3 solana_zk_sdk::{
4 encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
5 zk_elgamal_proof_program::proof_data::{
6 BatchedGroupedCiphertext3HandlesValidityProofContext, BatchedRangeProofContext,
7 CiphertextCommitmentEqualityProofContext,
8 },
9 },
10};
11
12pub struct MintPubkeys {
14 pub destination: PodElGamalPubkey,
15 pub supply: PodElGamalPubkey,
16 pub auditor: PodElGamalPubkey,
17}
18
19pub struct MintProofContext {
22 pub mint_amount_ciphertext_lo: PodMintAmountCiphertext,
23 pub mint_amount_ciphertext_hi: PodMintAmountCiphertext,
24 pub mint_pubkeys: MintPubkeys,
25 pub new_supply_ciphertext: PodElGamalCiphertext,
26}
27
28impl MintProofContext {
29 pub fn verify_and_extract(
30 equality_proof_context: &CiphertextCommitmentEqualityProofContext,
31 ciphertext_validity_proof_context: &BatchedGroupedCiphertext3HandlesValidityProofContext,
32 range_proof_context: &BatchedRangeProofContext,
33 ) -> Result<Self, TokenProofExtractionError> {
34 let CiphertextCommitmentEqualityProofContext {
41 pubkey: supply_elgamal_pubkey_from_equality_proof,
42 ciphertext: new_supply_ciphertext,
43 commitment: new_supply_commitment,
44 } = equality_proof_context;
45
46 let BatchedGroupedCiphertext3HandlesValidityProofContext {
51 first_pubkey: destination_elgamal_pubkey,
52 second_pubkey: supply_elgamal_pubkey_from_ciphertext_validity_proof,
53 third_pubkey: auditor_elgamal_pubkey,
54 grouped_ciphertext_lo: mint_amount_ciphertext_lo,
55 grouped_ciphertext_hi: mint_amount_ciphertext_hi,
56 } = ciphertext_validity_proof_context;
57
58 let BatchedRangeProofContext {
65 commitments: range_proof_commitments,
66 bit_lengths: range_proof_bit_lengths,
67 } = range_proof_context;
68
69 if supply_elgamal_pubkey_from_equality_proof
72 != supply_elgamal_pubkey_from_ciphertext_validity_proof
73 {
74 return Err(TokenProofExtractionError::ElGamalPubkeyMismatch);
75 }
76
77 let mint_amount_commitment_lo = mint_amount_ciphertext_lo.extract_commitment();
80 let mint_amount_commitment_hi = mint_amount_ciphertext_hi.extract_commitment();
81
82 let expected_commitments = [
83 *new_supply_commitment,
84 mint_amount_commitment_lo,
85 mint_amount_commitment_hi,
86 ];
88
89 if !range_proof_commitments
93 .iter()
94 .zip(expected_commitments.iter())
95 .all(|(proof_commitment, expected_commitment)| proof_commitment == expected_commitment)
96 {
97 return Err(TokenProofExtractionError::PedersenCommitmentMismatch);
98 }
99
100 const NEW_SUPPLY_BIT_LENGTH: u8 = 64;
102 const MINT_AMOUNT_LO_BIT_LENGTH: u8 = 16;
103 const MINT_AMOUNT_HI_BIT_LENGTH: u8 = 32;
104 const PADDING_BIT_LENGTH: u8 = 16;
105 let expected_bit_lengths = [
106 NEW_SUPPLY_BIT_LENGTH,
107 MINT_AMOUNT_LO_BIT_LENGTH,
108 MINT_AMOUNT_HI_BIT_LENGTH,
109 PADDING_BIT_LENGTH,
110 ]
111 .iter();
112
113 if !range_proof_bit_lengths
117 .iter()
118 .zip(expected_bit_lengths)
119 .all(|(proof_len, expected_len)| proof_len == expected_len)
120 {
121 return Err(TokenProofExtractionError::RangeProofLengthMismatch);
122 }
123
124 let mint_pubkeys = MintPubkeys {
125 destination: *destination_elgamal_pubkey,
126 supply: *supply_elgamal_pubkey_from_equality_proof,
127 auditor: *auditor_elgamal_pubkey,
128 };
129
130 Ok(MintProofContext {
131 mint_amount_ciphertext_lo: PodMintAmountCiphertext(*mint_amount_ciphertext_lo),
132 mint_amount_ciphertext_hi: PodMintAmountCiphertext(*mint_amount_ciphertext_hi),
133 mint_pubkeys,
134 new_supply_ciphertext: *new_supply_ciphertext,
135 })
136 }
137}