solana_zk_token_sdk/instruction/
ciphertext_commitment_equality.rs1#[cfg(not(target_os = "solana"))]
9use {
10 crate::{
11 encryption::{
12 elgamal::{ElGamalCiphertext, ElGamalKeypair},
13 pedersen::{PedersenCommitment, PedersenOpening},
14 },
15 errors::{ProofGenerationError, ProofVerificationError},
16 sigma_proofs::ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
17 transcript::TranscriptProtocol,
18 },
19 merlin::Transcript,
20 std::convert::TryInto,
21};
22use {
23 crate::{
24 instruction::{ProofType, ZkProofData},
25 zk_token_elgamal::pod,
26 },
27 bytemuck_derive::{Pod, Zeroable},
28};
29#[derive(Clone, Copy, Pod, Zeroable)]
35#[repr(C)]
36pub struct CiphertextCommitmentEqualityProofData {
37 pub context: CiphertextCommitmentEqualityProofContext,
38 pub proof: pod::CiphertextCommitmentEqualityProof,
39}
40
41#[derive(Clone, Copy, Pod, Zeroable)]
43#[repr(C)]
44pub struct CiphertextCommitmentEqualityProofContext {
45 pub pubkey: pod::ElGamalPubkey, pub ciphertext: pod::ElGamalCiphertext, pub commitment: pod::PedersenCommitment, }
54
55#[cfg(not(target_os = "solana"))]
56impl CiphertextCommitmentEqualityProofData {
57 pub fn new(
58 keypair: &ElGamalKeypair,
59 ciphertext: &ElGamalCiphertext,
60 commitment: &PedersenCommitment,
61 opening: &PedersenOpening,
62 amount: u64,
63 ) -> Result<Self, ProofGenerationError> {
64 let context = CiphertextCommitmentEqualityProofContext {
65 pubkey: pod::ElGamalPubkey(keypair.pubkey().into()),
66 ciphertext: pod::ElGamalCiphertext(ciphertext.to_bytes()),
67 commitment: pod::PedersenCommitment(commitment.to_bytes()),
68 };
69 let mut transcript = context.new_transcript();
70 let proof = CiphertextCommitmentEqualityProof::new(
71 keypair,
72 ciphertext,
73 opening,
74 amount,
75 &mut transcript,
76 );
77 Ok(CiphertextCommitmentEqualityProofData {
78 context,
79 proof: proof.into(),
80 })
81 }
82}
83
84impl ZkProofData<CiphertextCommitmentEqualityProofContext>
85 for CiphertextCommitmentEqualityProofData
86{
87 const PROOF_TYPE: ProofType = ProofType::CiphertextCommitmentEquality;
88
89 fn context_data(&self) -> &CiphertextCommitmentEqualityProofContext {
90 &self.context
91 }
92
93 #[cfg(not(target_os = "solana"))]
94 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
95 let mut transcript = self.context.new_transcript();
96
97 let pubkey = self.context.pubkey.try_into()?;
98 let ciphertext = self.context.ciphertext.try_into()?;
99 let commitment = self.context.commitment.try_into()?;
100 let proof: CiphertextCommitmentEqualityProof = self.proof.try_into()?;
101
102 proof
103 .verify(&pubkey, &ciphertext, &commitment, &mut transcript)
104 .map_err(|e| e.into())
105 }
106}
107
108#[allow(non_snake_case)]
109#[cfg(not(target_os = "solana"))]
110impl CiphertextCommitmentEqualityProofContext {
111 fn new_transcript(&self) -> Transcript {
112 let mut transcript = Transcript::new(b"CtxtCommEqualityProof");
113 transcript.append_pubkey(b"pubkey", &self.pubkey);
114 transcript.append_ciphertext(b"ciphertext", &self.ciphertext);
115 transcript.append_commitment(b"commitment", &self.commitment);
116 transcript
117 }
118}
119
120#[cfg(test)]
121mod test {
122 use {
123 super::*,
124 crate::encryption::{elgamal::ElGamalKeypair, pedersen::Pedersen},
125 };
126
127 #[test]
128 fn test_ctxt_comm_equality_proof_correctness() {
129 let keypair = ElGamalKeypair::new_rand();
130 let amount: u64 = 55;
131 let ciphertext = keypair.pubkey().encrypt(amount);
132 let (commitment, opening) = Pedersen::new(amount);
133
134 let proof_data = CiphertextCommitmentEqualityProofData::new(
135 &keypair,
136 &ciphertext,
137 &commitment,
138 &opening,
139 amount,
140 )
141 .unwrap();
142
143 assert!(proof_data.verify_proof().is_ok());
144 }
145}