solana_zk_token_sdk/instruction/batched_range_proof/
batched_range_proof_u256.rs1#[cfg(not(target_os = "solana"))]
4use {
5 crate::{
6 encryption::pedersen::{PedersenCommitment, PedersenOpening},
7 errors::{ProofGenerationError, ProofVerificationError},
8 instruction::batched_range_proof::{MAX_COMMITMENTS, MAX_SINGLE_BIT_LENGTH},
9 range_proof::RangeProof,
10 },
11 std::convert::TryInto,
12};
13use {
14 crate::{
15 instruction::{batched_range_proof::BatchedRangeProofContext, ProofType, ZkProofData},
16 zk_token_elgamal::pod,
17 },
18 bytemuck_derive::{Pod, Zeroable},
19};
20
21#[cfg(not(target_os = "solana"))]
22const BATCHED_RANGE_PROOF_U256_BIT_LENGTH: usize = 256;
23
24#[derive(Clone, Copy, Pod, Zeroable)]
30#[repr(C)]
31pub struct BatchedRangeProofU256Data {
32 pub context: BatchedRangeProofContext,
34
35 pub proof: pod::RangeProofU256,
37}
38
39#[cfg(not(target_os = "solana"))]
40impl BatchedRangeProofU256Data {
41 pub fn new(
42 commitments: Vec<&PedersenCommitment>,
43 amounts: Vec<u64>,
44 bit_lengths: Vec<usize>,
45 openings: Vec<&PedersenOpening>,
46 ) -> Result<Self, ProofGenerationError> {
47 if bit_lengths
49 .iter()
50 .any(|length| *length > MAX_SINGLE_BIT_LENGTH)
51 {
52 return Err(ProofGenerationError::IllegalCommitmentLength);
53 }
54
55 let batched_bit_length = bit_lengths
57 .iter()
58 .try_fold(0_usize, |acc, &x| acc.checked_add(x))
59 .ok_or(ProofGenerationError::IllegalAmountBitLength)?;
60 if batched_bit_length != BATCHED_RANGE_PROOF_U256_BIT_LENGTH {
61 return Err(ProofGenerationError::IllegalAmountBitLength);
62 }
63
64 let context =
65 BatchedRangeProofContext::new(&commitments, &amounts, &bit_lengths, &openings)?;
66
67 let mut transcript = context.new_transcript();
68 let proof = RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
69 .try_into()
70 .map_err(|_| ProofGenerationError::ProofLength)?;
71
72 Ok(Self { context, proof })
73 }
74}
75
76impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU256Data {
77 const PROOF_TYPE: ProofType = ProofType::BatchedRangeProofU256;
78
79 fn context_data(&self) -> &BatchedRangeProofContext {
80 &self.context
81 }
82
83 #[cfg(not(target_os = "solana"))]
84 fn verify_proof(&self) -> Result<(), ProofVerificationError> {
85 let (commitments, bit_lengths) = self.context.try_into()?;
86 let num_commitments = commitments.len();
87
88 if bit_lengths
89 .iter()
90 .any(|length| *length > MAX_SINGLE_BIT_LENGTH)
91 {
92 return Err(ProofVerificationError::IllegalCommitmentLength);
93 }
94
95 if num_commitments > MAX_COMMITMENTS || num_commitments != bit_lengths.len() {
96 return Err(ProofVerificationError::IllegalCommitmentLength);
97 }
98
99 let mut transcript = self.context_data().new_transcript();
100 let proof: RangeProof = self.proof.try_into()?;
101
102 proof
103 .verify(commitments.iter().collect(), bit_lengths, &mut transcript)
104 .map_err(|e| e.into())
105 }
106}
107
108#[cfg(test)]
109mod test {
110 use {
111 super::*,
112 crate::{
113 encryption::pedersen::Pedersen, errors::ProofVerificationError,
114 range_proof::errors::RangeProofVerificationError,
115 },
116 };
117
118 #[test]
119 fn test_batched_range_proof_256_instruction_correctness() {
120 let amount_1 = 4294967295_u64;
121 let amount_2 = 77_u64;
122 let amount_3 = 99_u64;
123 let amount_4 = 99_u64;
124 let amount_5 = 11_u64;
125 let amount_6 = 33_u64;
126 let amount_7 = 99_u64;
127 let amount_8 = 99_u64;
128
129 let (commitment_1, opening_1) = Pedersen::new(amount_1);
130 let (commitment_2, opening_2) = Pedersen::new(amount_2);
131 let (commitment_3, opening_3) = Pedersen::new(amount_3);
132 let (commitment_4, opening_4) = Pedersen::new(amount_4);
133 let (commitment_5, opening_5) = Pedersen::new(amount_5);
134 let (commitment_6, opening_6) = Pedersen::new(amount_6);
135 let (commitment_7, opening_7) = Pedersen::new(amount_7);
136 let (commitment_8, opening_8) = Pedersen::new(amount_8);
137
138 let proof_data = BatchedRangeProofU256Data::new(
139 vec![
140 &commitment_1,
141 &commitment_2,
142 &commitment_3,
143 &commitment_4,
144 &commitment_5,
145 &commitment_6,
146 &commitment_7,
147 &commitment_8,
148 ],
149 vec![
150 amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
151 ],
152 vec![32, 32, 32, 32, 32, 32, 32, 32],
153 vec![
154 &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
155 &opening_8,
156 ],
157 )
158 .unwrap();
159
160 assert!(proof_data.verify_proof().is_ok());
161
162 let amount_1 = 4294967296_u64; let amount_2 = 77_u64;
164 let amount_3 = 99_u64;
165 let amount_4 = 99_u64;
166 let amount_5 = 11_u64;
167 let amount_6 = 33_u64;
168 let amount_7 = 99_u64;
169 let amount_8 = 99_u64;
170
171 let (commitment_1, opening_1) = Pedersen::new(amount_1);
172 let (commitment_2, opening_2) = Pedersen::new(amount_2);
173 let (commitment_3, opening_3) = Pedersen::new(amount_3);
174 let (commitment_4, opening_4) = Pedersen::new(amount_4);
175 let (commitment_5, opening_5) = Pedersen::new(amount_5);
176 let (commitment_6, opening_6) = Pedersen::new(amount_6);
177 let (commitment_7, opening_7) = Pedersen::new(amount_7);
178 let (commitment_8, opening_8) = Pedersen::new(amount_8);
179
180 let proof_data = BatchedRangeProofU256Data::new(
181 vec![
182 &commitment_1,
183 &commitment_2,
184 &commitment_3,
185 &commitment_4,
186 &commitment_5,
187 &commitment_6,
188 &commitment_7,
189 &commitment_8,
190 ],
191 vec![
192 amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
193 ],
194 vec![32, 32, 32, 32, 32, 32, 32, 32],
195 vec![
196 &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
197 &opening_8,
198 ],
199 )
200 .unwrap();
201
202 assert_eq!(
203 proof_data.verify_proof().unwrap_err(),
204 ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
205 );
206 }
207}