1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use group::ff::Field;
use pasta_curves::arithmetic::CurveAffine;
use rand_core::OsRng;
use super::{verify_proof, VerificationStrategy};
use crate::{
multicore::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator},
plonk::{Error, VerifyingKey},
poly::commitment::{Guard, Params, MSM},
transcript::{Blake2bRead, EncodedChallenge},
};
#[derive(Debug)]
struct BatchStrategy<'params, C: CurveAffine> {
msm: MSM<'params, C>,
}
impl<'params, C: CurveAffine> BatchStrategy<'params, C> {
fn new(params: &'params Params<C>) -> Self {
BatchStrategy {
msm: MSM::new(params),
}
}
}
impl<'params, C: CurveAffine> VerificationStrategy<'params, C> for BatchStrategy<'params, C> {
type Output = MSM<'params, C>;
fn process<E: EncodedChallenge<C>>(
self,
f: impl FnOnce(MSM<'params, C>) -> Result<Guard<'params, C, E>, Error>,
) -> Result<Self::Output, Error> {
let guard = f(self.msm)?;
Ok(guard.use_challenges())
}
}
#[derive(Debug)]
struct BatchItem<C: CurveAffine> {
instances: Vec<Vec<Vec<C::Scalar>>>,
proof: Vec<u8>,
}
#[derive(Debug, Default)]
pub struct BatchVerifier<C: CurveAffine> {
items: Vec<BatchItem<C>>,
}
impl<C: CurveAffine> BatchVerifier<C> {
pub fn new() -> Self {
Self { items: vec![] }
}
pub fn add_proof(&mut self, instances: Vec<Vec<Vec<C::Scalar>>>, proof: Vec<u8>) {
self.items.push(BatchItem { instances, proof })
}
pub fn finalize(self, params: &Params<C>, vk: &VerifyingKey<C>) -> bool {
fn accumulate_msm<'params, C: CurveAffine>(
mut acc: MSM<'params, C>,
msm: MSM<'params, C>,
) -> MSM<'params, C> {
acc.scale(C::Scalar::random(OsRng));
acc.add_msm(&msm);
acc
}
let final_msm = self
.items
.into_par_iter()
.enumerate()
.map(|(i, item)| {
let instances: Vec<Vec<_>> = item
.instances
.iter()
.map(|i| i.iter().map(|c| &c[..]).collect())
.collect();
let instances: Vec<_> = instances.iter().map(|i| &i[..]).collect();
let strategy = BatchStrategy::new(params);
let mut transcript = Blake2bRead::init(&item.proof[..]);
verify_proof(params, vk, strategy, &instances, &mut transcript).map_err(|e| {
tracing::debug!("Batch item {} failed verification: {}", i, e);
e
})
})
.try_fold(
|| params.empty_msm(),
|msm, res| res.map(|proof_msm| accumulate_msm(msm, proof_msm)),
)
.try_reduce(|| params.empty_msm(), |a, b| Ok(accumulate_msm(a, b)));
match final_msm {
Ok(msm) => msm.eval(),
Err(_) => false,
}
}
}