solana_zk_token_sdk/instruction/grouped_ciphertext_validity/
handles_3.rs1#[cfg(not(target_os = "solana"))]
14use {
15 crate::{
16 encryption::{
17 elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
18 pedersen::PedersenOpening,
19 },
20 errors::{ProofGenerationError, ProofVerificationError},
21 sigma_proofs::grouped_ciphertext_validity_proof::GroupedCiphertext3HandlesValidityProof,
22 transcript::TranscriptProtocol,
23 },
24 merlin::Transcript,
25};
26use {
27 crate::{
28 instruction::{ProofType, ZkProofData},
29 zk_token_elgamal::pod,
30 },
31 bytemuck_derive::{Pod, Zeroable},
32};
33
34#[derive(Clone, Copy, Pod, Zeroable)]
40#[repr(C)]
41pub struct GroupedCiphertext3HandlesValidityProofData {
42 pub context: GroupedCiphertext3HandlesValidityProofContext,
43
44 pub proof: pod::GroupedCiphertext3HandlesValidityProof,
45}
46
47#[derive(Clone, Copy, Pod, Zeroable)]
48#[repr(C)]
49pub struct GroupedCiphertext3HandlesValidityProofContext {
50 pub source_pubkey: pod::ElGamalPubkey, pub destination_pubkey: pod::ElGamalPubkey, pub auditor_pubkey: pod::ElGamalPubkey, pub grouped_ciphertext: pod::GroupedElGamalCiphertext3Handles, }
58
59#[cfg(not(target_os = "solana"))]
60impl GroupedCiphertext3HandlesValidityProofData {
61 pub fn new(
62 source_pubkey: &ElGamalPubkey,
63 destination_pubkey: &ElGamalPubkey,
64 auditor_pubkey: &ElGamalPubkey,
65 grouped_ciphertext: &GroupedElGamalCiphertext<3>,
66 amount: u64,
67 opening: &PedersenOpening,
68 ) -> Result<Self, ProofGenerationError> {
69 let pod_source_pubkey = pod::ElGamalPubkey(source_pubkey.into());
70 let pod_destination_pubkey = pod::ElGamalPubkey(destination_pubkey.into());
71 let pod_auditor_pubkey = pod::ElGamalPubkey(auditor_pubkey.into());
72 let pod_grouped_ciphertext = (*grouped_ciphertext).into();
73
74 let context = GroupedCiphertext3HandlesValidityProofContext {
75 source_pubkey: pod_source_pubkey,
76 destination_pubkey: pod_destination_pubkey,
77 auditor_pubkey: pod_auditor_pubkey,
78 grouped_ciphertext: pod_grouped_ciphertext,
79 };
80
81 let mut transcript = context.new_transcript();
82
83 let proof = GroupedCiphertext3HandlesValidityProof::new(
84 source_pubkey,
85 destination_pubkey,
86 auditor_pubkey,
87 amount,
88 opening,
89 &mut transcript,
90 )
91 .into();
92
93 Ok(Self { context, proof })
94 }
95}
96
97impl ZkProofData<GroupedCiphertext3HandlesValidityProofContext>
98 for GroupedCiphertext3HandlesValidityProofData
99{
100 const PROOF_TYPE: ProofType = ProofType::GroupedCiphertext3HandlesValidity;
101
102 fn context_data(&self) -> &GroupedCiphertext3HandlesValidityProofContext {
103 &self.context
104 }
105
106 #[cfg(not(target_os = "solana"))]
107 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
108 let mut transcript = self.context.new_transcript();
109
110 let source_pubkey = self.context.source_pubkey.try_into()?;
111 let destination_pubkey = self.context.destination_pubkey.try_into()?;
112 let auditor_pubkey = self.context.auditor_pubkey.try_into()?;
113 let grouped_ciphertext: GroupedElGamalCiphertext<3> =
114 self.context.grouped_ciphertext.try_into()?;
115
116 let source_handle = grouped_ciphertext.handles.first().unwrap();
117 let destination_handle = grouped_ciphertext.handles.get(1).unwrap();
118 let auditor_handle = grouped_ciphertext.handles.get(2).unwrap();
119
120 let proof: GroupedCiphertext3HandlesValidityProof = self.proof.try_into()?;
121
122 proof
123 .verify(
124 &grouped_ciphertext.commitment,
125 &source_pubkey,
126 &destination_pubkey,
127 &auditor_pubkey,
128 source_handle,
129 destination_handle,
130 auditor_handle,
131 &mut transcript,
132 )
133 .map_err(|e| e.into())
134 }
135}
136
137#[cfg(not(target_os = "solana"))]
138impl GroupedCiphertext3HandlesValidityProofContext {
139 fn new_transcript(&self) -> Transcript {
140 let mut transcript = Transcript::new(b"GroupedCiphertext3HandlesValidityProof");
141
142 transcript.append_pubkey(b"source-pubkey", &self.source_pubkey);
143 transcript.append_pubkey(b"destination-pubkey", &self.destination_pubkey);
144 transcript.append_pubkey(b"auditor-pubkey", &self.auditor_pubkey);
145 transcript
146 .append_grouped_ciphertext_3_handles(b"grouped-ciphertext", &self.grouped_ciphertext);
147
148 transcript
149 }
150}
151
152#[cfg(test)]
153mod test {
154 use {
155 super::*,
156 crate::encryption::{elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal},
157 };
158
159 #[test]
160 fn test_ciphertext_validity_proof_instruction_correctness() {
161 let source_keypair = ElGamalKeypair::new_rand();
162 let source_pubkey = source_keypair.pubkey();
163
164 let destination_keypair = ElGamalKeypair::new_rand();
165 let destination_pubkey = destination_keypair.pubkey();
166
167 let auditor_keypair = ElGamalKeypair::new_rand();
168 let auditor_pubkey = auditor_keypair.pubkey();
169
170 let amount: u64 = 55;
171 let opening = PedersenOpening::new_rand();
172 let grouped_ciphertext = GroupedElGamal::encrypt_with(
173 [source_pubkey, destination_pubkey, auditor_pubkey],
174 amount,
175 &opening,
176 );
177
178 let proof_data = GroupedCiphertext3HandlesValidityProofData::new(
179 source_pubkey,
180 destination_pubkey,
181 auditor_pubkey,
182 &grouped_ciphertext,
183 amount,
184 &opening,
185 )
186 .unwrap();
187
188 assert!(proof_data.verify_proof().is_ok());
189 }
190}