solana_zk_token_sdk/instruction/
fee_sigma.rs1#[cfg(not(target_os = "solana"))]
12use {
13 crate::{
14 encryption::pedersen::{PedersenCommitment, PedersenOpening},
15 errors::{ProofGenerationError, ProofVerificationError},
16 sigma_proofs::fee_proof::FeeSigmaProof,
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
30#[derive(Clone, Copy, Pod, Zeroable)]
35#[repr(C)]
36pub struct FeeSigmaProofData {
37 pub context: FeeSigmaProofContext,
38
39 pub proof: pod::FeeSigmaProof,
40}
41
42#[derive(Clone, Copy, Pod, Zeroable)]
48#[repr(C)]
49pub struct FeeSigmaProofContext {
50 pub fee_commitment: pod::PedersenCommitment,
52
53 pub delta_commitment: pod::PedersenCommitment,
55
56 pub claimed_commitment: pod::PedersenCommitment,
58
59 pub max_fee: pod::PodU64,
61}
62
63#[cfg(not(target_os = "solana"))]
64impl FeeSigmaProofData {
65 pub fn new(
66 fee_commitment: &PedersenCommitment,
67 delta_commitment: &PedersenCommitment,
68 claimed_commitment: &PedersenCommitment,
69 fee_opening: &PedersenOpening,
70 delta_opening: &PedersenOpening,
71 claimed_opening: &PedersenOpening,
72 fee_amount: u64,
73 delta_fee: u64,
74 max_fee: u64,
75 ) -> Result<Self, ProofGenerationError> {
76 let pod_fee_commitment = pod::PedersenCommitment(fee_commitment.to_bytes());
77 let pod_delta_commitment = pod::PedersenCommitment(delta_commitment.to_bytes());
78 let pod_claimed_commitment = pod::PedersenCommitment(claimed_commitment.to_bytes());
79 let pod_max_fee = max_fee.into();
80
81 let context = FeeSigmaProofContext {
82 fee_commitment: pod_fee_commitment,
83 delta_commitment: pod_delta_commitment,
84 claimed_commitment: pod_claimed_commitment,
85 max_fee: pod_max_fee,
86 };
87
88 let mut transcript = context.new_transcript();
89
90 let proof = FeeSigmaProof::new(
91 (fee_amount, fee_commitment, fee_opening),
92 (delta_fee, delta_commitment, delta_opening),
93 (claimed_commitment, claimed_opening),
94 max_fee,
95 &mut transcript,
96 )
97 .into();
98
99 Ok(Self { context, proof })
100 }
101}
102
103impl ZkProofData<FeeSigmaProofContext> for FeeSigmaProofData {
104 const PROOF_TYPE: ProofType = ProofType::FeeSigma;
105
106 fn context_data(&self) -> &FeeSigmaProofContext {
107 &self.context
108 }
109
110 #[cfg(not(target_os = "solana"))]
111 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
112 let mut transcript = self.context.new_transcript();
113
114 let fee_commitment = self.context.fee_commitment.try_into()?;
115 let delta_commitment = self.context.delta_commitment.try_into()?;
116 let claimed_commitment = self.context.claimed_commitment.try_into()?;
117 let max_fee = self.context.max_fee.into();
118 let proof: FeeSigmaProof = self.proof.try_into()?;
119
120 proof
121 .verify(
122 &fee_commitment,
123 &delta_commitment,
124 &claimed_commitment,
125 max_fee,
126 &mut transcript,
127 )
128 .map_err(|e| e.into())
129 }
130}
131
132#[cfg(not(target_os = "solana"))]
133impl FeeSigmaProofContext {
134 fn new_transcript(&self) -> Transcript {
135 let mut transcript = Transcript::new(b"FeeSigmaProof");
136 transcript.append_commitment(b"fee-commitment", &self.fee_commitment);
137 transcript.append_commitment(b"delta-commitment", &self.fee_commitment);
138 transcript.append_commitment(b"claimed-commitment", &self.fee_commitment);
139 transcript.append_u64(b"max-fee", self.max_fee.into());
140 transcript
141 }
142}
143
144#[cfg(test)]
145mod test {
146 use {super::*, crate::encryption::pedersen::Pedersen, curve25519_dalek::scalar::Scalar};
147
148 #[test]
149 fn test_fee_sigma_instruction_correctness() {
150 let transfer_amount: u64 = 1;
152 let max_fee: u64 = 3;
153
154 let fee_rate: u16 = 400;
155 let fee_amount: u64 = 1;
156 let delta_fee: u64 = 9600;
157
158 let (transfer_commitment, transfer_opening) = Pedersen::new(transfer_amount);
159 let (fee_commitment, fee_opening) = Pedersen::new(fee_amount);
160
161 let scalar_rate = Scalar::from(fee_rate);
162 let delta_commitment =
163 &fee_commitment * Scalar::from(10_000_u64) - &transfer_commitment * &scalar_rate;
164 let delta_opening =
165 &fee_opening * &Scalar::from(10_000_u64) - &transfer_opening * &scalar_rate;
166
167 let (claimed_commitment, claimed_opening) = Pedersen::new(delta_fee);
168
169 let proof_data = FeeSigmaProofData::new(
170 &fee_commitment,
171 &delta_commitment,
172 &claimed_commitment,
173 &fee_opening,
174 &delta_opening,
175 &claimed_opening,
176 fee_amount,
177 delta_fee,
178 max_fee,
179 )
180 .unwrap();
181
182 assert!(proof_data.verify_proof().is_ok());
183
184 let transfer_amount: u64 = 55;
186 let max_fee: u64 = 3;
187
188 let fee_rate: u16 = 555;
189 let fee_amount: u64 = 4;
190
191 let (transfer_commitment, transfer_opening) = Pedersen::new(transfer_amount);
192 let (fee_commitment, fee_opening) = Pedersen::new(max_fee);
193
194 let scalar_rate = Scalar::from(fee_rate);
195 let delta_commitment =
196 &fee_commitment * &Scalar::from(10000_u64) - &transfer_commitment * &scalar_rate;
197 let delta_opening =
198 &fee_opening * &Scalar::from(10000_u64) - &transfer_opening * &scalar_rate;
199
200 let (claimed_commitment, claimed_opening) = Pedersen::new(0_u64);
201
202 let proof_data = FeeSigmaProofData::new(
203 &fee_commitment,
204 &delta_commitment,
205 &claimed_commitment,
206 &fee_opening,
207 &delta_opening,
208 &claimed_opening,
209 fee_amount,
210 delta_fee,
211 max_fee,
212 )
213 .unwrap();
214
215 assert!(proof_data.verify_proof().is_ok());
216 }
217}