1use groth16_solana::{
18 decompression::{decompress_g1, decompress_g2},
19 groth16::{Groth16Verifier, Groth16Verifyingkey},
20};
21use thiserror::Error;
22
23use crate::verifying_keys::*;
24
25pub mod verifying_keys;
26#[derive(Debug, Error, PartialEq)]
27pub enum VerifierError {
28 #[error("PublicInputsTryIntoFailed")]
29 PublicInputsTryIntoFailed,
30 #[error("DecompressG1Failed")]
31 DecompressG1Failed,
32 #[error("DecompressG2Failed")]
33 DecompressG2Failed,
34 #[error("InvalidPublicInputsLength")]
35 InvalidPublicInputsLength,
36 #[error("CreateGroth16VerifierFailed")]
37 CreateGroth16VerifierFailed,
38 #[error("ProofVerificationFailed")]
39 ProofVerificationFailed,
40 #[error("InvalidBatchSize supported batch sizes are 1, 10, 100, 500, 1000")]
41 InvalidBatchSize,
42}
43
44impl From<VerifierError> for u32 {
45 fn from(e: VerifierError) -> u32 {
46 match e {
47 PublicInputsTryIntoFailed => 13001,
48 DecompressG1Failed => 13002,
49 DecompressG2Failed => 13003,
50 InvalidPublicInputsLength => 13004,
51 CreateGroth16VerifierFailed => 13005,
52 ProofVerificationFailed => 13006,
53 InvalidBatchSize => 13007,
54 }
55 }
56}
57
58#[cfg(feature = "solana")]
59impl From<VerifierError> for solana_program_error::ProgramError {
60 fn from(e: VerifierError) -> Self {
61 solana_program_error::ProgramError::Custom(e.into())
62 }
63}
64
65#[cfg(feature = "pinocchio")]
66impl From<VerifierError> for pinocchio::program_error::ProgramError {
67 fn from(e: VerifierError) -> Self {
68 pinocchio::program_error::ProgramError::Custom(e.into())
69 }
70}
71
72pub use light_compressed_account::instruction_data::compressed_proof::CompressedProof;
73use VerifierError::*;
74
75pub fn verify_create_addresses_proof(
76 address_roots: &[[u8; 32]],
77 addresses: &[[u8; 32]],
78 compressed_proof: &CompressedProof,
79) -> Result<(), VerifierError> {
80 let public_inputs = [address_roots, addresses].concat();
81 match addresses.len() {
82 1 => verify::<2>(
83 &public_inputs
84 .try_into()
85 .map_err(|_| PublicInputsTryIntoFailed)?,
86 compressed_proof,
87 &v1_non_inclusion_26_1::VERIFYINGKEY,
88 ),
89 2 => verify::<4>(
90 &public_inputs
91 .try_into()
92 .map_err(|_| PublicInputsTryIntoFailed)?,
93 compressed_proof,
94 &v1_non_inclusion_26_2::VERIFYINGKEY,
95 ),
96 3 => verify::<6>(
97 &public_inputs
98 .try_into()
99 .map_err(|_| PublicInputsTryIntoFailed)?,
100 compressed_proof,
101 &v1_non_inclusion_26_3::VERIFYINGKEY,
102 ),
103 4 => verify::<8>(
104 &public_inputs
105 .try_into()
106 .map_err(|_| PublicInputsTryIntoFailed)?,
107 compressed_proof,
108 &v1_non_inclusion_26_4::VERIFYINGKEY,
109 ),
110 8 => verify::<16>(
111 &public_inputs
112 .try_into()
113 .map_err(|_| PublicInputsTryIntoFailed)?,
114 compressed_proof,
115 &v1_non_inclusion_26_8::VERIFYINGKEY,
116 ),
117 _ => Err(InvalidPublicInputsLength),
118 }
119}
120
121#[inline(never)]
122pub fn verify_create_addresses_and_inclusion_proof(
123 roots: &[[u8; 32]],
124 leaves: &[[u8; 32]],
125 address_roots: &[[u8; 32]],
126 addresses: &[[u8; 32]],
127 compressed_proof: &CompressedProof,
128) -> Result<(), VerifierError> {
129 let public_inputs = [roots, leaves, address_roots, addresses].concat();
130 match public_inputs.len() {
140 4 => verify::<4>(
141 &public_inputs
142 .try_into()
143 .map_err(|_| PublicInputsTryIntoFailed)?,
144 compressed_proof,
145 &v1_combined_26_26_1_1::VERIFYINGKEY,
146 ),
147 6 => {
148 let verifying_key = if address_roots.len() == 1 {
149 &v1_combined_26_26_2_1::VERIFYINGKEY
150 } else {
151 &v1_combined_26_26_1_2::VERIFYINGKEY
152 };
153 verify::<6>(
154 &public_inputs
155 .try_into()
156 .map_err(|_| PublicInputsTryIntoFailed)?,
157 compressed_proof,
158 verifying_key,
159 )
160 }
161 8 => {
162 let verifying_key = if address_roots.len() == 1 {
163 &v1_combined_26_26_3_1::VERIFYINGKEY
164 } else {
165 &v1_combined_26_26_2_2::VERIFYINGKEY
166 };
167 verify::<8>(
168 &public_inputs
169 .try_into()
170 .map_err(|_| PublicInputsTryIntoFailed)?,
171 compressed_proof,
172 verifying_key,
173 )
174 }
175 10 => {
176 let verifying_key = if address_roots.len() == 1 {
177 &v1_combined_26_26_4_1::VERIFYINGKEY
178 } else {
179 &v1_combined_26_26_3_2::VERIFYINGKEY
180 };
181 verify::<10>(
182 &public_inputs
183 .try_into()
184 .map_err(|_| PublicInputsTryIntoFailed)?,
185 compressed_proof,
186 verifying_key,
187 )
188 }
189 12 => verify::<12>(
190 &public_inputs
191 .try_into()
192 .map_err(|_| PublicInputsTryIntoFailed)?,
193 compressed_proof,
194 &v1_combined_26_26_4_2::VERIFYINGKEY,
195 ),
196 _ => Err(InvalidPublicInputsLength),
197 }
198}
199
200#[inline(never)]
201pub fn verify_inclusion_proof(
202 roots: &[[u8; 32]],
203 leaves: &[[u8; 32]],
204 compressed_proof: &CompressedProof,
205) -> Result<(), VerifierError> {
206 let public_inputs = [roots, leaves].concat();
207
208 match public_inputs.len() {
215 2 => verify::<2>(
216 &public_inputs
217 .try_into()
218 .map_err(|_| PublicInputsTryIntoFailed)?,
219 compressed_proof,
220 &v1_inclusion_26_1::VERIFYINGKEY,
221 ),
222 4 => verify::<4>(
223 &public_inputs
224 .try_into()
225 .map_err(|_| PublicInputsTryIntoFailed)?,
226 compressed_proof,
227 &v1_inclusion_26_2::VERIFYINGKEY,
228 ),
229 6 => verify::<6>(
230 &public_inputs
231 .try_into()
232 .map_err(|_| PublicInputsTryIntoFailed)?,
233 compressed_proof,
234 &v1_inclusion_26_3::VERIFYINGKEY,
235 ),
236 8 => verify::<8>(
237 &public_inputs
238 .try_into()
239 .map_err(|_| PublicInputsTryIntoFailed)?,
240 compressed_proof,
241 &v1_inclusion_26_4::VERIFYINGKEY,
242 ),
243 16 => verify::<16>(
244 &public_inputs
245 .try_into()
246 .map_err(|_| PublicInputsTryIntoFailed)?,
247 compressed_proof,
248 &v1_inclusion_26_8::VERIFYINGKEY,
249 ),
250 _ => Err(InvalidPublicInputsLength),
251 }
252}
253
254pub fn select_verifying_key<'a>(
255 num_leaves: usize,
256 num_addresses: usize,
257) -> Result<&'a Groth16Verifyingkey<'static>, VerifierError> {
258 #[cfg(all(feature = "solana", target_os = "solana"))]
259 solana_msg::msg!(
260 "select_verifying_key num_leaves: {}, num_addresses: {}",
261 num_leaves,
262 num_addresses
263 );
264 match (num_leaves, num_addresses) {
265 (1, 1) => Ok(&v2_combined_32_40_1_1::VERIFYINGKEY),
267 (1, 2) => Ok(&v2_combined_32_40_1_2::VERIFYINGKEY),
268 (1, 3) => Ok(&v2_combined_32_40_1_3::VERIFYINGKEY),
269 (1, 4) => Ok(&v2_combined_32_40_1_4::VERIFYINGKEY),
270 (2, 1) => Ok(&v2_combined_32_40_2_1::VERIFYINGKEY),
271 (2, 2) => Ok(&v2_combined_32_40_2_2::VERIFYINGKEY),
272 (2, 3) => Ok(&v2_combined_32_40_2_3::VERIFYINGKEY),
273 (2, 4) => Ok(&v2_combined_32_40_2_4::VERIFYINGKEY),
274 (3, 1) => Ok(&v2_combined_32_40_3_1::VERIFYINGKEY),
275 (3, 2) => Ok(&v2_combined_32_40_3_2::VERIFYINGKEY),
276 (3, 3) => Ok(&v2_combined_32_40_3_3::VERIFYINGKEY),
277 (3, 4) => Ok(&v2_combined_32_40_3_4::VERIFYINGKEY),
278 (4, 1) => Ok(&v2_combined_32_40_4_1::VERIFYINGKEY),
279 (4, 2) => Ok(&v2_combined_32_40_4_2::VERIFYINGKEY),
280 (4, 3) => Ok(&v2_combined_32_40_4_3::VERIFYINGKEY),
281 (4, 4) => Ok(&v2_combined_32_40_4_4::VERIFYINGKEY),
282
283 (1, _) => Ok(&v2_inclusion_32_1::VERIFYINGKEY),
285 (2, _) => Ok(&v2_inclusion_32_2::VERIFYINGKEY),
286 (3, _) => Ok(&v2_inclusion_32_3::VERIFYINGKEY),
287 (4, _) => Ok(&v2_inclusion_32_4::VERIFYINGKEY),
288 (5, _) => Ok(&v2_inclusion_32_5::VERIFYINGKEY),
289 (6, _) => Ok(&v2_inclusion_32_6::VERIFYINGKEY),
290 (7, _) => Ok(&v2_inclusion_32_7::VERIFYINGKEY),
291 (8, _) => Ok(&v2_inclusion_32_8::VERIFYINGKEY),
292 (9, _) => Ok(&v2_inclusion_32_9::VERIFYINGKEY),
293 (10, _) => Ok(&v2_inclusion_32_10::VERIFYINGKEY),
294 (11, _) => Ok(&v2_inclusion_32_11::VERIFYINGKEY),
295 (12, _) => Ok(&v2_inclusion_32_12::VERIFYINGKEY),
296 (13, _) => Ok(&v2_inclusion_32_13::VERIFYINGKEY),
297 (14, _) => Ok(&v2_inclusion_32_14::VERIFYINGKEY),
298 (15, _) => Ok(&v2_inclusion_32_15::VERIFYINGKEY),
299 (16, _) => Ok(&v2_inclusion_32_16::VERIFYINGKEY),
300 (17, _) => Ok(&v2_inclusion_32_17::VERIFYINGKEY),
301 (18, _) => Ok(&v2_inclusion_32_18::VERIFYINGKEY),
302 (19, _) => Ok(&v2_inclusion_32_19::VERIFYINGKEY),
303 (20, _) => Ok(&v2_inclusion_32_20::VERIFYINGKEY),
304
305 (_, 1) => Ok(&v2_non_inclusion_40_1::VERIFYINGKEY),
307 (_, 2) => Ok(&v2_non_inclusion_40_2::VERIFYINGKEY),
308 (_, 3) => Ok(&v2_non_inclusion_40_3::VERIFYINGKEY),
309 (_, 4) => Ok(&v2_non_inclusion_40_4::VERIFYINGKEY),
310 (_, 5) => Ok(&v2_non_inclusion_40_5::VERIFYINGKEY),
311 (_, 6) => Ok(&v2_non_inclusion_40_6::VERIFYINGKEY),
312 (_, 7) => Ok(&v2_non_inclusion_40_7::VERIFYINGKEY),
313 (_, 8) => Ok(&v2_non_inclusion_40_8::VERIFYINGKEY),
314 (_, 9) => Ok(&v2_non_inclusion_40_9::VERIFYINGKEY),
315 (_, 10) => Ok(&v2_non_inclusion_40_10::VERIFYINGKEY),
316 (_, 11) => Ok(&v2_non_inclusion_40_11::VERIFYINGKEY),
317 (_, 12) => Ok(&v2_non_inclusion_40_12::VERIFYINGKEY),
318 (_, 13) => Ok(&v2_non_inclusion_40_13::VERIFYINGKEY),
319 (_, 14) => Ok(&v2_non_inclusion_40_14::VERIFYINGKEY),
320 (_, 15) => Ok(&v2_non_inclusion_40_15::VERIFYINGKEY),
321 (_, 16) => Ok(&v2_non_inclusion_40_16::VERIFYINGKEY),
322 (_, 17) => Ok(&v2_non_inclusion_40_17::VERIFYINGKEY),
323 (_, 18) => Ok(&v2_non_inclusion_40_18::VERIFYINGKEY),
324 (_, 19) => Ok(&v2_non_inclusion_40_19::VERIFYINGKEY),
325 (_, 20) => Ok(&v2_non_inclusion_40_20::VERIFYINGKEY),
326 (_, 21) => Ok(&v2_non_inclusion_40_21::VERIFYINGKEY),
327 (_, 22) => Ok(&v2_non_inclusion_40_22::VERIFYINGKEY),
328 (_, 23) => Ok(&v2_non_inclusion_40_23::VERIFYINGKEY),
329 (_, 24) => Ok(&v2_non_inclusion_40_24::VERIFYINGKEY),
330 (_, 25) => Ok(&v2_non_inclusion_40_25::VERIFYINGKEY),
331 (_, 26) => Ok(&v2_non_inclusion_40_26::VERIFYINGKEY),
332 (_, 27) => Ok(&v2_non_inclusion_40_27::VERIFYINGKEY),
333 (_, 28) => Ok(&v2_non_inclusion_40_28::VERIFYINGKEY),
334 (_, 29) => Ok(&v2_non_inclusion_40_29::VERIFYINGKEY),
335 (_, 30) => Ok(&v2_non_inclusion_40_30::VERIFYINGKEY),
336 (_, 31) => Ok(&v2_non_inclusion_40_31::VERIFYINGKEY),
337 (_, 32) => Ok(&v2_non_inclusion_40_32::VERIFYINGKEY),
338
339 _ => Err(InvalidPublicInputsLength),
341 }
342}
343
344#[inline(never)]
345pub fn verify<const N: usize>(
346 public_inputs: &[[u8; 32]; N],
347 proof: &CompressedProof,
348 vk: &Groth16Verifyingkey,
349) -> Result<(), VerifierError> {
350 let proof_a = decompress_g1(&proof.a).map_err(|_| DecompressG1Failed)?;
351 let proof_b = decompress_g2(&proof.b).map_err(|_| DecompressG2Failed)?;
352 let proof_c = decompress_g1(&proof.c).map_err(|_| DecompressG1Failed)?;
353 let mut verifier = Groth16Verifier::new(&proof_a, &proof_b, &proof_c, public_inputs, vk)
354 .map_err(|_| {
355 #[cfg(all(target_os = "solana", feature = "solana"))]
356 {
357 use solana_msg::msg;
358 msg!("Proof verification failed");
359 msg!("Public inputs: {:?}", public_inputs);
360 msg!("Proof A: {:?}", proof_a);
361 msg!("Proof B: {:?}", proof_b);
362 msg!("Proof C: {:?}", proof_c);
363 }
364 CreateGroth16VerifierFailed
365 })?;
366 verifier.verify().map_err(|_| {
367 #[cfg(all(target_os = "solana", feature = "solana"))]
368 {
369 use solana_msg::msg;
370 msg!("Proof verification failed");
371 msg!("Public inputs: {:?}", public_inputs);
372 msg!("Proof A: {:?}", proof_a);
373 msg!("Proof B: {:?}", proof_b);
374 msg!("Proof C: {:?}", proof_c);
375 }
376 ProofVerificationFailed
377 })?;
378 Ok(())
379}
380
381#[inline(never)]
382pub fn verify_batch_append_with_proofs(
383 batch_size: u64,
384 public_input_hash: [u8; 32],
385 compressed_proof: &CompressedProof,
386) -> Result<(), VerifierError> {
387 match batch_size {
388 10 => verify::<1>(
389 &[public_input_hash],
390 compressed_proof,
391 &batch_append_32_10::VERIFYINGKEY,
392 ),
393 500 => verify::<1>(
394 &[public_input_hash],
395 compressed_proof,
396 &batch_append_32_500::VERIFYINGKEY,
397 ),
398 _ => Err(InvalidPublicInputsLength),
399 }
400}
401
402#[inline(never)]
403pub fn verify_batch_update(
404 batch_size: u64,
405 public_input_hash: [u8; 32],
406 compressed_proof: &CompressedProof,
407) -> Result<(), VerifierError> {
408 match batch_size {
409 10 => verify::<1>(
410 &[public_input_hash],
411 compressed_proof,
412 &batch_update_32_10::VERIFYINGKEY,
413 ),
414 500 => verify::<1>(
415 &[public_input_hash],
416 compressed_proof,
417 &batch_update_32_500::VERIFYINGKEY,
418 ),
419 _ => Err(InvalidPublicInputsLength),
420 }
421}
422
423#[inline(never)]
424pub fn verify_batch_address_update(
425 batch_size: u64,
426 public_input_hash: [u8; 32],
427 compressed_proof: &CompressedProof,
428) -> Result<(), VerifierError> {
429 match batch_size {
430 10 => verify::<1>(
431 &[public_input_hash],
432 compressed_proof,
433 &batch_address_append_40_10::VERIFYINGKEY,
434 ),
435 250 => verify::<1>(
436 &[public_input_hash],
437 compressed_proof,
438 &batch_address_append_40_250::VERIFYINGKEY,
439 ),
440 _ => Err(InvalidPublicInputsLength),
441 }
442}