halo2_axiom/plonk/verifier/
batch.rs
1use ff::FromUniformBytes;
2use group::ff::Field;
3use halo2curves::CurveAffine;
4use rand_core::OsRng;
5
6use super::{verify_proof, VerificationStrategy};
7use crate::{
8 multicore::{IntoParallelIterator, TryFoldAndReduce},
9 plonk::{Error, VerifyingKey},
10 poly::{
11 commitment::{Params, MSM},
12 ipa::{
13 commitment::{IPACommitmentScheme, ParamsVerifierIPA},
14 msm::MSMIPA,
15 multiopen::VerifierIPA,
16 strategy::GuardIPA,
17 },
18 },
19 transcript::{Blake2bRead, TranscriptReadBuffer},
20};
21
22#[cfg(feature = "multicore")]
23use crate::multicore::{IndexedParallelIterator, ParallelIterator};
24
25#[derive(Debug)]
29struct BatchStrategy<'params, C: CurveAffine> {
30 msm: MSMIPA<'params, C>,
31}
32
33impl<'params, C: CurveAffine>
34 VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<'params, C>>
35 for BatchStrategy<'params, C>
36{
37 type Output = MSMIPA<'params, C>;
38
39 fn new(params: &'params ParamsVerifierIPA<C>) -> Self {
40 BatchStrategy {
41 msm: MSMIPA::new(params),
42 }
43 }
44
45 fn process(
46 self,
47 f: impl FnOnce(MSMIPA<'params, C>) -> Result<GuardIPA<'params, C>, Error>,
48 ) -> Result<Self::Output, Error> {
49 let guard = f(self.msm)?;
50 Ok(guard.use_challenges())
51 }
52
53 fn finalize(self) -> bool {
54 unreachable!()
55 }
56}
57
58#[derive(Debug)]
59struct BatchItem<C: CurveAffine> {
60 instances: Vec<Vec<Vec<C::ScalarExt>>>,
61 proof: Vec<u8>,
62}
63
64#[derive(Debug, Default)]
67pub struct BatchVerifier<C: CurveAffine> {
68 items: Vec<BatchItem<C>>,
69}
70
71impl<C: CurveAffine> BatchVerifier<C>
72where
73 C::Scalar: FromUniformBytes<64>,
74{
75 pub fn new() -> Self {
77 Self { items: vec![] }
78 }
79
80 pub fn add_proof(&mut self, instances: Vec<Vec<Vec<C::Scalar>>>, proof: Vec<u8>) {
82 self.items.push(BatchItem { instances, proof })
83 }
84
85 pub fn finalize(self, params: &ParamsVerifierIPA<C>, vk: &VerifyingKey<C>) -> bool {
94 fn accumulate_msm<'params, C: CurveAffine>(
95 mut acc: MSMIPA<'params, C>,
96 msm: MSMIPA<'params, C>,
97 ) -> MSMIPA<'params, C> {
98 acc.scale(C::Scalar::random(OsRng));
102
103 acc.add_msm(&msm);
104 acc
105 }
106
107 let final_msm = self
108 .items
109 .into_par_iter()
110 .enumerate()
111 .map(|(i, item)| {
112 let instances: Vec<Vec<_>> = item
113 .instances
114 .iter()
115 .map(|i| i.iter().map(|c| &c[..]).collect())
116 .collect();
117 let instances: Vec<_> = instances.iter().map(|i| &i[..]).collect();
118
119 let strategy = BatchStrategy::new(params);
120 let mut transcript = Blake2bRead::init(&item.proof[..]);
121 verify_proof(params, vk, strategy, &instances, &mut transcript).map_err(|e| {
122 tracing::debug!("Batch item {} failed verification: {}", i, e);
123 e
124 })
125 })
126 .try_fold_and_reduce(
127 || params.empty_msm(),
128 |acc, res| res.map(|proof_msm| accumulate_msm(acc, proof_msm)),
129 );
130
131 match final_msm {
132 Ok(msm) => msm.check(),
133 Err(_) => false,
134 }
135 }
136}