solana_zk_sdk/zk_elgamal_proof_program/proof_data/
zero_ciphertext.rs1#[cfg(target_arch = "wasm32")]
8use wasm_bindgen::prelude::*;
9#[cfg(not(target_os = "solana"))]
10use {
11 crate::{
12 encryption::elgamal::{ElGamalCiphertext, ElGamalKeypair},
13 sigma_proofs::zero_ciphertext::ZeroCiphertextProof,
14 zk_elgamal_proof_program::{
15 errors::{ProofGenerationError, ProofVerificationError},
16 proof_data::errors::ProofDataError,
17 },
18 },
19 bytemuck::bytes_of,
20 merlin::Transcript,
21 std::convert::TryInto,
22};
23use {
24 crate::{
25 encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
26 sigma_proofs::pod::PodZeroCiphertextProof,
27 zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
28 },
29 bytemuck_derive::{Pod, Zeroable},
30};
31
32#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
37#[derive(Clone, Copy, Pod, Zeroable)]
38#[repr(C)]
39pub struct ZeroCiphertextProofData {
40 pub context: ZeroCiphertextProofContext, pub proof: PodZeroCiphertextProof, }
46
47#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
49#[derive(Clone, Copy, Pod, Zeroable)]
50#[repr(C)]
51pub struct ZeroCiphertextProofContext {
52 pub pubkey: PodElGamalPubkey, pub ciphertext: PodElGamalCiphertext, }
58
59#[cfg(not(target_os = "solana"))]
60#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
61impl ZeroCiphertextProofData {
62 pub fn new(
63 keypair: &ElGamalKeypair,
64 ciphertext: &ElGamalCiphertext,
65 ) -> Result<Self, ProofGenerationError> {
66 let pod_pubkey = PodElGamalPubkey(keypair.pubkey().into());
67 let pod_ciphertext = PodElGamalCiphertext(ciphertext.to_bytes());
68
69 let context = ZeroCiphertextProofContext {
70 pubkey: pod_pubkey,
71 ciphertext: pod_ciphertext,
72 };
73
74 let mut transcript = context.new_transcript();
75 let proof = ZeroCiphertextProof::new(keypair, ciphertext, &mut transcript).into();
76
77 Ok(ZeroCiphertextProofData { context, proof })
78 }
79}
80
81impl_wasm_to_bytes!(TYPE = ZeroCiphertextProofData);
82
83impl ZkProofData<ZeroCiphertextProofContext> for ZeroCiphertextProofData {
84 const PROOF_TYPE: ProofType = ProofType::ZeroCiphertext;
85
86 fn context_data(&self) -> &ZeroCiphertextProofContext {
87 &self.context
88 }
89
90 #[cfg(not(target_os = "solana"))]
91 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
92 let mut transcript = self.context.new_transcript();
93 let pubkey = self.context.pubkey.try_into()?;
94 let ciphertext = self.context.ciphertext.try_into()?;
95 let proof: ZeroCiphertextProof = self.proof.try_into()?;
96 proof
97 .verify(&pubkey, &ciphertext, &mut transcript)
98 .map_err(|e| e.into())
99 }
100}
101
102#[allow(non_snake_case)]
103#[cfg(not(target_os = "solana"))]
104impl ZeroCiphertextProofContext {
105 fn new_transcript(&self) -> Transcript {
106 let mut transcript = Transcript::new(b"zero-ciphertext-instruction");
107
108 transcript.append_message(b"pubkey", bytes_of(&self.pubkey));
109 transcript.append_message(b"ciphertext", bytes_of(&self.ciphertext));
110
111 transcript
112 }
113}
114
115impl_wasm_to_bytes!(TYPE = ZeroCiphertextProofContext);
116
117#[cfg(test)]
118mod test {
119 use super::*;
120
121 #[test]
122 fn test_zero_ciphertext_proof_instruction_correctness() {
123 let keypair = ElGamalKeypair::new_rand();
124
125 let ciphertext = keypair.pubkey().encrypt(0_u64);
127 let zero_ciphertext_proof_data =
128 ZeroCiphertextProofData::new(&keypair, &ciphertext).unwrap();
129 assert!(zero_ciphertext_proof_data.verify_proof().is_ok());
130
131 let ciphertext = keypair.pubkey().encrypt(1_u64);
133 let zero_ciphertext_proof_data =
134 ZeroCiphertextProofData::new(&keypair, &ciphertext).unwrap();
135 assert!(zero_ciphertext_proof_data.verify_proof().is_err());
136 }
137}