1use alloc::vec::Vec;
2
3use halo2_proofs::plonk;
4use pasta_curves::vesta;
5use rand::{CryptoRng, RngCore};
6use tracing::debug;
7
8use super::{Authorized, Bundle};
9use crate::{
10 circuit::VerifyingKey,
11 primitives::redpallas::{self, Binding, SpendAuth},
12};
13
14#[derive(Debug)]
16struct BundleSignature {
17 signature: redpallas::batch::Item<SpendAuth, Binding>,
19}
20
21#[derive(Debug, Default)]
25pub struct BatchValidator {
26 proofs: plonk::BatchVerifier<vesta::Affine>,
27 signatures: Vec<BundleSignature>,
28}
29
30impl BatchValidator {
31 pub fn new() -> Self {
33 BatchValidator {
34 proofs: plonk::BatchVerifier::new(),
35 signatures: vec![],
36 }
37 }
38
39 pub fn add_bundle<V: Copy + Into<i64>>(
41 &mut self,
42 bundle: &Bundle<Authorized, V>,
43 sighash: [u8; 32],
44 ) {
45 for action in bundle.actions().iter() {
46 self.signatures.push(BundleSignature {
47 signature: action
48 .rk()
49 .create_batch_item(action.authorization().clone(), &sighash),
50 });
51 }
52
53 self.signatures.push(BundleSignature {
54 signature: bundle
55 .binding_validating_key()
56 .create_batch_item(bundle.authorization().binding_signature().clone(), &sighash),
57 });
58
59 bundle
60 .authorization()
61 .proof()
62 .add_to_batch(&mut self.proofs, bundle.to_instances());
63 }
64
65 pub fn validate<R: RngCore + CryptoRng>(self, vk: &VerifyingKey, rng: R) -> bool {
72 if self.signatures.is_empty() {
75 return true;
79 }
80
81 let mut validator = redpallas::batch::Verifier::new();
82 for sig in self.signatures.iter() {
83 validator.queue(sig.signature.clone());
84 }
85
86 match validator.verify(rng) {
87 Ok(()) => self.proofs.finalize(&vk.params, &vk.vk),
89 Err(e) => {
90 debug!("RedPallas batch validation failed: {}", e);
91 false
92 }
93 }
94 }
95}