solana_zk_token_sdk/instruction/batched_grouped_ciphertext_validity/
handles_2.rs1#[cfg(not(target_os = "solana"))]
16use {
17 crate::{
18 encryption::{
19 elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
20 pedersen::PedersenOpening,
21 },
22 errors::{ProofGenerationError, ProofVerificationError},
23 sigma_proofs::batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
24 transcript::TranscriptProtocol,
25 },
26 merlin::Transcript,
27};
28use {
29 crate::{
30 instruction::{ProofType, ZkProofData},
31 zk_token_elgamal::pod,
32 },
33 bytemuck_derive::{Pod, Zeroable},
34};
35
36#[derive(Clone, Copy, Pod, Zeroable)]
42#[repr(C)]
43pub struct BatchedGroupedCiphertext2HandlesValidityProofData {
44 pub context: BatchedGroupedCiphertext2HandlesValidityProofContext,
45
46 pub proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
47}
48
49#[derive(Clone, Copy, Pod, Zeroable)]
50#[repr(C)]
51pub struct BatchedGroupedCiphertext2HandlesValidityProofContext {
52 pub destination_pubkey: pod::ElGamalPubkey, pub auditor_pubkey: pod::ElGamalPubkey, pub grouped_ciphertext_lo: pod::GroupedElGamalCiphertext2Handles, pub grouped_ciphertext_hi: pod::GroupedElGamalCiphertext2Handles, }
60
61#[cfg(not(target_os = "solana"))]
62impl BatchedGroupedCiphertext2HandlesValidityProofData {
63 pub fn new(
64 destination_pubkey: &ElGamalPubkey,
65 auditor_pubkey: &ElGamalPubkey,
66 grouped_ciphertext_lo: &GroupedElGamalCiphertext<2>,
67 grouped_ciphertext_hi: &GroupedElGamalCiphertext<2>,
68 amount_lo: u64,
69 amount_hi: u64,
70 opening_lo: &PedersenOpening,
71 opening_hi: &PedersenOpening,
72 ) -> Result<Self, ProofGenerationError> {
73 let pod_destination_pubkey = pod::ElGamalPubkey(destination_pubkey.into());
74 let pod_auditor_pubkey = pod::ElGamalPubkey(auditor_pubkey.into());
75 let pod_grouped_ciphertext_lo = (*grouped_ciphertext_lo).into();
76 let pod_grouped_ciphertext_hi = (*grouped_ciphertext_hi).into();
77
78 let context = BatchedGroupedCiphertext2HandlesValidityProofContext {
79 destination_pubkey: pod_destination_pubkey,
80 auditor_pubkey: pod_auditor_pubkey,
81 grouped_ciphertext_lo: pod_grouped_ciphertext_lo,
82 grouped_ciphertext_hi: pod_grouped_ciphertext_hi,
83 };
84
85 let mut transcript = context.new_transcript();
86
87 let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
88 (destination_pubkey, auditor_pubkey),
89 (amount_lo, amount_hi),
90 (opening_lo, opening_hi),
91 &mut transcript,
92 )
93 .into();
94
95 Ok(Self { context, proof })
96 }
97}
98
99impl ZkProofData<BatchedGroupedCiphertext2HandlesValidityProofContext>
100 for BatchedGroupedCiphertext2HandlesValidityProofData
101{
102 const PROOF_TYPE: ProofType = ProofType::BatchedGroupedCiphertext2HandlesValidity;
103
104 fn context_data(&self) -> &BatchedGroupedCiphertext2HandlesValidityProofContext {
105 &self.context
106 }
107
108 #[cfg(not(target_os = "solana"))]
109 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
110 let mut transcript = self.context.new_transcript();
111
112 let destination_pubkey = self.context.destination_pubkey.try_into()?;
113 let auditor_pubkey = self.context.auditor_pubkey.try_into()?;
114 let grouped_ciphertext_lo: GroupedElGamalCiphertext<2> =
115 self.context.grouped_ciphertext_lo.try_into()?;
116 let grouped_ciphertext_hi: GroupedElGamalCiphertext<2> =
117 self.context.grouped_ciphertext_hi.try_into()?;
118
119 let destination_handle_lo = grouped_ciphertext_lo.handles.first().unwrap();
120 let auditor_handle_lo = grouped_ciphertext_lo.handles.get(1).unwrap();
121
122 let destination_handle_hi = grouped_ciphertext_hi.handles.first().unwrap();
123 let auditor_handle_hi = grouped_ciphertext_hi.handles.get(1).unwrap();
124
125 let proof: BatchedGroupedCiphertext2HandlesValidityProof = self.proof.try_into()?;
126
127 proof
128 .verify(
129 (&destination_pubkey, &auditor_pubkey),
130 (
131 &grouped_ciphertext_lo.commitment,
132 &grouped_ciphertext_hi.commitment,
133 ),
134 (destination_handle_lo, destination_handle_hi),
135 (auditor_handle_lo, auditor_handle_hi),
136 &mut transcript,
137 )
138 .map_err(|e| e.into())
139 }
140}
141
142#[cfg(not(target_os = "solana"))]
143impl BatchedGroupedCiphertext2HandlesValidityProofContext {
144 fn new_transcript(&self) -> Transcript {
145 let mut transcript = Transcript::new(b"BatchedGroupedCiphertextValidityProof");
146
147 transcript.append_pubkey(b"destination-pubkey", &self.destination_pubkey);
148 transcript.append_pubkey(b"auditor-pubkey", &self.auditor_pubkey);
149 transcript.append_grouped_ciphertext_2_handles(
150 b"grouped-ciphertext-lo",
151 &self.grouped_ciphertext_lo,
152 );
153 transcript.append_grouped_ciphertext_2_handles(
154 b"grouped-ciphertext-hi",
155 &self.grouped_ciphertext_hi,
156 );
157
158 transcript
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use {
165 super::*,
166 crate::encryption::{elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal},
167 };
168
169 #[test]
170 fn test_ciphertext_validity_proof_instruction_correctness() {
171 let destination_keypair = ElGamalKeypair::new_rand();
172 let destination_pubkey = destination_keypair.pubkey();
173
174 let auditor_keypair = ElGamalKeypair::new_rand();
175 let auditor_pubkey = auditor_keypair.pubkey();
176
177 let amount_lo: u64 = 11;
178 let amount_hi: u64 = 22;
179
180 let opening_lo = PedersenOpening::new_rand();
181 let opening_hi = PedersenOpening::new_rand();
182
183 let grouped_ciphertext_lo = GroupedElGamal::encrypt_with(
184 [destination_pubkey, auditor_pubkey],
185 amount_lo,
186 &opening_lo,
187 );
188
189 let grouped_ciphertext_hi = GroupedElGamal::encrypt_with(
190 [destination_pubkey, auditor_pubkey],
191 amount_hi,
192 &opening_hi,
193 );
194
195 let proof_data = BatchedGroupedCiphertext2HandlesValidityProofData::new(
196 destination_pubkey,
197 auditor_pubkey,
198 &grouped_ciphertext_lo,
199 &grouped_ciphertext_hi,
200 amount_lo,
201 amount_hi,
202 &opening_lo,
203 &opening_hi,
204 )
205 .unwrap();
206
207 assert!(proof_data.verify_proof().is_ok());
208 }
209}