solana_zk_token_sdk/instruction/
zero_balance.rs1#[cfg(not(target_os = "solana"))]
8use {
9 crate::{
10 encryption::elgamal::{ElGamalCiphertext, ElGamalKeypair},
11 errors::{ProofGenerationError, ProofVerificationError},
12 sigma_proofs::zero_balance_proof::ZeroBalanceProof,
13 transcript::TranscriptProtocol,
14 },
15 merlin::Transcript,
16 std::convert::TryInto,
17};
18use {
19 crate::{
20 instruction::{ProofType, ZkProofData},
21 zk_token_elgamal::pod,
22 },
23 bytemuck_derive::{Pod, Zeroable},
24};
25
26#[derive(Clone, Copy, Pod, Zeroable)]
31#[repr(C)]
32pub struct ZeroBalanceProofData {
33 pub context: ZeroBalanceProofContext, pub proof: pod::ZeroBalanceProof, }
39
40#[derive(Clone, Copy, Pod, Zeroable)]
42#[repr(C)]
43pub struct ZeroBalanceProofContext {
44 pub pubkey: pod::ElGamalPubkey, pub ciphertext: pod::ElGamalCiphertext, }
50
51#[cfg(not(target_os = "solana"))]
52impl ZeroBalanceProofData {
53 pub fn new(
54 keypair: &ElGamalKeypair,
55 ciphertext: &ElGamalCiphertext,
56 ) -> Result<Self, ProofGenerationError> {
57 let pod_pubkey = pod::ElGamalPubkey(keypair.pubkey().into());
58 let pod_ciphertext = pod::ElGamalCiphertext(ciphertext.to_bytes());
59
60 let context = ZeroBalanceProofContext {
61 pubkey: pod_pubkey,
62 ciphertext: pod_ciphertext,
63 };
64
65 let mut transcript = context.new_transcript();
66 let proof = ZeroBalanceProof::new(keypair, ciphertext, &mut transcript).into();
67
68 Ok(ZeroBalanceProofData { context, proof })
69 }
70}
71
72impl ZkProofData<ZeroBalanceProofContext> for ZeroBalanceProofData {
73 const PROOF_TYPE: ProofType = ProofType::ZeroBalance;
74
75 fn context_data(&self) -> &ZeroBalanceProofContext {
76 &self.context
77 }
78
79 #[cfg(not(target_os = "solana"))]
80 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
81 let mut transcript = self.context.new_transcript();
82 let pubkey = self.context.pubkey.try_into()?;
83 let ciphertext = self.context.ciphertext.try_into()?;
84 let proof: ZeroBalanceProof = self.proof.try_into()?;
85 proof
86 .verify(&pubkey, &ciphertext, &mut transcript)
87 .map_err(|e| e.into())
88 }
89}
90
91#[allow(non_snake_case)]
92#[cfg(not(target_os = "solana"))]
93impl ZeroBalanceProofContext {
94 fn new_transcript(&self) -> Transcript {
95 let mut transcript = Transcript::new(b"ZeroBalanceProof");
96
97 transcript.append_pubkey(b"pubkey", &self.pubkey);
98 transcript.append_ciphertext(b"ciphertext", &self.ciphertext);
99
100 transcript
101 }
102}
103
104#[cfg(test)]
105mod test {
106 use super::*;
107
108 #[test]
109 fn test_zero_balance_proof_instruction_correctness() {
110 let keypair = ElGamalKeypair::new_rand();
111
112 let ciphertext = keypair.pubkey().encrypt(0_u64);
114 let zero_balance_proof_data = ZeroBalanceProofData::new(&keypair, &ciphertext).unwrap();
115 assert!(zero_balance_proof_data.verify_proof().is_ok());
116
117 let ciphertext = keypair.pubkey().encrypt(1_u64);
119 let zero_balance_proof_data = ZeroBalanceProofData::new(&keypair, &ciphertext).unwrap();
120 assert!(zero_balance_proof_data.verify_proof().is_err());
121 }
122}