spl_token_confidential_transfer_proof_generation/
mint.rs1#[cfg(target_arch = "wasm32")]
38use solana_zk_sdk::encryption::grouped_elgamal::GroupedElGamalCiphertext3Handles;
39use {
40 crate::{
41 encryption::MintAmountCiphertext, errors::TokenProofGenerationError,
42 try_combine_lo_hi_ciphertexts, try_split_u64, CiphertextValidityProofWithAuditorCiphertext,
43 },
44 solana_zk_sdk::{
45 encryption::{
46 elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
47 pedersen::Pedersen,
48 },
49 zk_elgamal_proof_program::proof_data::{
50 BatchedGroupedCiphertext3HandlesValidityProofData, BatchedRangeProofU128Data,
51 CiphertextCommitmentEqualityProofData, ZkProofData,
52 },
53 },
54};
55
56const NEW_SUPPLY_BIT_LENGTH: usize = 64;
57const MINT_AMOUNT_LO_BIT_LENGTH: usize = 16;
58const MINT_AMOUNT_HI_BIT_LENGTH: usize = 32;
59const RANGE_PROOF_PADDING_BIT_LENGTH: usize = 16;
61
62pub struct MintProofData {
64 pub equality_proof_data: CiphertextCommitmentEqualityProofData,
65 pub ciphertext_validity_proof_data_with_ciphertext:
66 CiphertextValidityProofWithAuditorCiphertext,
67 pub range_proof_data: BatchedRangeProofU128Data,
68}
69
70pub fn mint_split_proof_data(
71 current_supply_ciphertext: &ElGamalCiphertext,
72 mint_amount: u64,
73 current_supply: u64,
74 supply_elgamal_keypair: &ElGamalKeypair,
75 destination_elgamal_pubkey: &ElGamalPubkey,
76 auditor_elgamal_pubkey: Option<&ElGamalPubkey>,
77) -> Result<MintProofData, TokenProofGenerationError> {
78 let default_auditor_pubkey = ElGamalPubkey::default();
79 let auditor_elgamal_pubkey = auditor_elgamal_pubkey.unwrap_or(&default_auditor_pubkey);
80
81 let (mint_amount_lo, mint_amount_hi) = try_split_u64(mint_amount, MINT_AMOUNT_LO_BIT_LENGTH)
83 .ok_or(TokenProofGenerationError::IllegalAmountBitLength)?;
84
85 let (mint_amount_grouped_ciphertext_lo, mint_amount_opening_lo) = MintAmountCiphertext::new(
88 mint_amount_lo,
89 destination_elgamal_pubkey,
90 supply_elgamal_keypair.pubkey(),
91 auditor_elgamal_pubkey,
92 );
93 #[cfg(not(target_arch = "wasm32"))]
94 let grouped_ciphertext_lo = mint_amount_grouped_ciphertext_lo.0;
95 #[cfg(target_arch = "wasm32")]
96 let grouped_ciphertext_lo = GroupedElGamalCiphertext3Handles::encrypt_with_u64(
97 destination_elgamal_pubkey,
98 supply_elgamal_keypair.pubkey(),
99 auditor_elgamal_pubkey,
100 mint_amount_lo,
101 &mint_amount_opening_lo,
102 );
103
104 let (mint_amount_grouped_ciphertext_hi, mint_amount_opening_hi) = MintAmountCiphertext::new(
105 mint_amount_hi,
106 destination_elgamal_pubkey,
107 supply_elgamal_keypair.pubkey(),
108 auditor_elgamal_pubkey,
109 );
110 #[cfg(not(target_arch = "wasm32"))]
111 let grouped_ciphertext_hi = mint_amount_grouped_ciphertext_hi.0;
112 #[cfg(target_arch = "wasm32")]
113 let grouped_ciphertext_hi = GroupedElGamalCiphertext3Handles::encrypt_with_u64(
114 destination_elgamal_pubkey,
115 supply_elgamal_keypair.pubkey(),
116 auditor_elgamal_pubkey,
117 mint_amount_hi,
118 &mint_amount_opening_hi,
119 );
120
121 let mint_amount_ciphertext_supply_lo = mint_amount_grouped_ciphertext_lo
123 .0
124 .to_elgamal_ciphertext(1)
125 .unwrap();
126 let mint_amount_ciphertext_supply_hi = mint_amount_grouped_ciphertext_hi
127 .0
128 .to_elgamal_ciphertext(1)
129 .unwrap();
130
131 #[allow(clippy::arithmetic_side_effects)]
132 let new_supply_ciphertext = current_supply_ciphertext
133 + try_combine_lo_hi_ciphertexts(
134 &mint_amount_ciphertext_supply_lo,
135 &mint_amount_ciphertext_supply_hi,
136 MINT_AMOUNT_LO_BIT_LENGTH,
137 )
138 .ok_or(TokenProofGenerationError::IllegalAmountBitLength)?;
139
140 let new_supply = current_supply
142 .checked_add(mint_amount)
143 .ok_or(TokenProofGenerationError::IllegalAmountBitLength)?;
144
145 let (new_supply_commitment, new_supply_opening) = Pedersen::new(new_supply);
146
147 let equality_proof_data = CiphertextCommitmentEqualityProofData::new(
149 supply_elgamal_keypair,
150 &new_supply_ciphertext,
151 &new_supply_commitment,
152 &new_supply_opening,
153 new_supply,
154 )
155 .map_err(TokenProofGenerationError::from)?;
156
157 let ciphertext_validity_proof_data = BatchedGroupedCiphertext3HandlesValidityProofData::new(
159 destination_elgamal_pubkey,
160 supply_elgamal_keypair.pubkey(),
161 auditor_elgamal_pubkey,
162 &grouped_ciphertext_lo,
163 &grouped_ciphertext_hi,
164 mint_amount_lo,
165 mint_amount_hi,
166 &mint_amount_opening_lo,
167 &mint_amount_opening_hi,
168 )
169 .map_err(TokenProofGenerationError::from)?;
170
171 let mint_amount_auditor_ciphertext_lo = ciphertext_validity_proof_data
172 .context_data()
173 .grouped_ciphertext_lo
174 .try_extract_ciphertext(2)
175 .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?;
176
177 let mint_amount_auditor_ciphertext_hi = ciphertext_validity_proof_data
178 .context_data()
179 .grouped_ciphertext_hi
180 .try_extract_ciphertext(2)
181 .map_err(|_| TokenProofGenerationError::CiphertextExtraction)?;
182
183 let ciphertext_validity_proof_data_with_ciphertext =
184 CiphertextValidityProofWithAuditorCiphertext {
185 proof_data: ciphertext_validity_proof_data,
186 ciphertext_lo: mint_amount_auditor_ciphertext_lo,
187 ciphertext_hi: mint_amount_auditor_ciphertext_hi,
188 };
189
190 let (padding_commitment, padding_opening) = Pedersen::new(0_u64);
196 let range_proof_data = BatchedRangeProofU128Data::new(
197 vec![
198 &new_supply_commitment,
199 mint_amount_grouped_ciphertext_lo.get_commitment(),
200 mint_amount_grouped_ciphertext_hi.get_commitment(),
201 &padding_commitment,
202 ],
203 vec![new_supply, mint_amount_lo, mint_amount_hi, 0],
204 vec![
205 NEW_SUPPLY_BIT_LENGTH,
206 MINT_AMOUNT_LO_BIT_LENGTH,
207 MINT_AMOUNT_HI_BIT_LENGTH,
208 RANGE_PROOF_PADDING_BIT_LENGTH,
209 ],
210 vec![
211 &new_supply_opening,
212 &mint_amount_opening_lo,
213 &mint_amount_opening_hi,
214 &padding_opening,
215 ],
216 )
217 .map_err(TokenProofGenerationError::from)?;
218
219 Ok(MintProofData {
220 equality_proof_data,
221 ciphertext_validity_proof_data_with_ciphertext,
222 range_proof_data,
223 })
224}