mirror of https://github.com/zcash/halo2.git
138 lines
4.4 KiB
Rust
138 lines
4.4 KiB
Rust
use crate::plonk::Error;
|
|
use group::ff::Field;
|
|
use halo2_middleware::ff::FromUniformBytes;
|
|
use halo2_middleware::zal::impls::H2cEngine;
|
|
use halo2curves::CurveAffine;
|
|
use rand_core::OsRng;
|
|
|
|
use super::{verify_proof, VerificationStrategy};
|
|
use crate::{
|
|
multicore::{
|
|
IndexedParallelIterator, IntoParallelIterator, ParallelIterator, TryFoldAndReduce,
|
|
},
|
|
plonk::VerifyingKey,
|
|
poly::{
|
|
commitment::{Params, MSM},
|
|
ipa::{
|
|
commitment::{IPACommitmentScheme, ParamsVerifierIPA},
|
|
msm::MSMIPA,
|
|
multiopen::VerifierIPA,
|
|
strategy::GuardIPA,
|
|
},
|
|
},
|
|
transcript::{Blake2bRead, TranscriptReadBuffer},
|
|
};
|
|
|
|
/// A proof verification strategy that returns the proof's MSM.
|
|
///
|
|
/// `BatchVerifier` handles the accumulation of the MSMs for the batched proofs.
|
|
#[derive(Debug)]
|
|
struct BatchStrategy<'params, C: CurveAffine> {
|
|
msm: MSMIPA<'params, C>,
|
|
}
|
|
|
|
impl<'params, C: CurveAffine> VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<C>>
|
|
for BatchStrategy<'params, C>
|
|
{
|
|
type Output = MSMIPA<'params, C>;
|
|
|
|
fn new(params: &'params ParamsVerifierIPA<C>) -> Self {
|
|
BatchStrategy {
|
|
msm: MSMIPA::new(params),
|
|
}
|
|
}
|
|
|
|
fn process(
|
|
self,
|
|
f: impl FnOnce(MSMIPA<'params, C>) -> Result<GuardIPA<'params, C>, Error>,
|
|
) -> Result<Self::Output, Error> {
|
|
let guard = f(self.msm)?;
|
|
Ok(guard.use_challenges())
|
|
}
|
|
|
|
fn finalize(self) -> bool {
|
|
unreachable!()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct BatchItem<C: CurveAffine> {
|
|
instances: Vec<Vec<Vec<C::ScalarExt>>>,
|
|
proof: Vec<u8>,
|
|
}
|
|
|
|
/// A verifier that checks multiple proofs in a batch. **This requires the
|
|
/// `batch` crate feature to be enabled.**
|
|
#[derive(Debug, Default)]
|
|
pub struct BatchVerifier<C: CurveAffine> {
|
|
items: Vec<BatchItem<C>>,
|
|
}
|
|
|
|
impl<C: CurveAffine> BatchVerifier<C>
|
|
where
|
|
C::Scalar: FromUniformBytes<64>,
|
|
{
|
|
/// Constructs a new batch verifier.
|
|
pub fn new() -> Self {
|
|
Self { items: vec![] }
|
|
}
|
|
|
|
/// Adds a proof to the batch.
|
|
pub fn add_proof(&mut self, instances: Vec<Vec<Vec<C::Scalar>>>, proof: Vec<u8>) {
|
|
self.items.push(BatchItem { instances, proof })
|
|
}
|
|
|
|
/// Finalizes the batch and checks its validity.
|
|
///
|
|
/// Returns `false` if *some* proof was invalid. If the caller needs to identify
|
|
/// specific failing proofs, it must re-process the proofs separately.
|
|
///
|
|
/// This uses [`OsRng`] internally instead of taking an `R: RngCore` argument, because
|
|
/// the internal parallelization requires access to a RNG that is guaranteed to not
|
|
/// clone its internal state when shared between threads.
|
|
pub fn finalize(self, params: &ParamsVerifierIPA<C>, vk: &VerifyingKey<C>) -> bool {
|
|
fn accumulate_msm<'params, C: CurveAffine>(
|
|
mut acc: MSMIPA<'params, C>,
|
|
msm: MSMIPA<'params, C>,
|
|
) -> MSMIPA<'params, C> {
|
|
// Scale the MSM by a random factor to ensure that if the existing MSM has
|
|
// `is_zero() == false` then this argument won't be able to interfere with it
|
|
// to make it true, with high probability.
|
|
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_and_reduce(
|
|
|| params.empty_msm(),
|
|
|acc, res| res.map(|proof_msm| accumulate_msm(acc, proof_msm)),
|
|
);
|
|
|
|
match final_msm {
|
|
// ZAL: Verification is (supposedly) cheap, hence we don't use an accelerator engine
|
|
Ok(msm) => msm.check(&H2cEngine::new()),
|
|
Err(_) => false,
|
|
}
|
|
}
|
|
}
|