mirror of https://github.com/zcash/halo2.git
171 lines
5.0 KiB
Rust
171 lines
5.0 KiB
Rust
use super::commitment::{IPACommitmentScheme, ParamsIPA};
|
|
use super::msm::MSMIPA;
|
|
use super::multiopen::VerifierIPA;
|
|
use crate::{
|
|
plonk::Error,
|
|
poly::{
|
|
commitment::MSM,
|
|
strategy::{Guard, VerificationStrategy},
|
|
},
|
|
};
|
|
use group::Curve;
|
|
use halo2_middleware::ff::Field;
|
|
use halo2_middleware::zal::{impls::H2cEngine, traits::MsmAccel};
|
|
use halo2curves::CurveAffine;
|
|
use rand_core::OsRng;
|
|
|
|
/// Wrapper for verification accumulator
|
|
#[derive(Debug, Clone)]
|
|
pub struct GuardIPA<'params, C: CurveAffine> {
|
|
pub(crate) msm: MSMIPA<'params, C>,
|
|
pub(crate) neg_c: C::Scalar,
|
|
pub(crate) u: Vec<C::Scalar>,
|
|
pub(crate) u_packed: Vec<C::Scalar>,
|
|
}
|
|
|
|
/// An accumulator instance consisting of an evaluation claim and a proof.
|
|
#[derive(Debug, Clone)]
|
|
pub struct Accumulator<C: CurveAffine> {
|
|
/// The claimed output of the linear-time polycommit opening protocol
|
|
pub g: C,
|
|
|
|
/// A vector of challenges u_0, ..., u_{k - 1} sampled by the verifier, to
|
|
/// be used in computing G'_0.
|
|
pub u_packed: Vec<C::Scalar>,
|
|
}
|
|
|
|
/// Define accumulator type as `MSMIPA`
|
|
impl<'params, C: CurveAffine> Guard<IPACommitmentScheme<C>> for GuardIPA<'params, C> {
|
|
type MSMAccumulator = MSMIPA<'params, C>;
|
|
}
|
|
|
|
/// IPA specific operations
|
|
impl<'params, C: CurveAffine> GuardIPA<'params, C> {
|
|
/// Lets caller supply the challenges and obtain an MSM with updated
|
|
/// scalars and points.
|
|
pub fn use_challenges(mut self) -> MSMIPA<'params, C> {
|
|
let s = compute_s(&self.u, self.neg_c);
|
|
self.msm.add_to_g_scalars(&s);
|
|
|
|
self.msm
|
|
}
|
|
|
|
/// Lets caller supply the purported G point and simply appends
|
|
/// [-c] G to return an updated MSM.
|
|
pub fn use_g(mut self, g: C) -> (MSMIPA<'params, C>, Accumulator<C>) {
|
|
self.msm.append_term(self.neg_c, g.into());
|
|
|
|
let accumulator = Accumulator {
|
|
g,
|
|
u_packed: self.u_packed,
|
|
};
|
|
|
|
(self.msm, accumulator)
|
|
}
|
|
|
|
/// Computes G = ⟨s, params.g⟩
|
|
pub fn compute_g(&self, engine: &impl MsmAccel<C>) -> C {
|
|
let s = compute_s(&self.u, C::Scalar::ONE);
|
|
engine.msm(&s, &self.msm.params.g).to_affine()
|
|
}
|
|
}
|
|
|
|
/// A verifier that checks multiple proofs in a batch.
|
|
#[derive(Debug)]
|
|
pub struct AccumulatorStrategy<'params, C: CurveAffine> {
|
|
msm: MSMIPA<'params, C>,
|
|
}
|
|
|
|
impl<'params, C: CurveAffine> VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<C>>
|
|
for AccumulatorStrategy<'params, C>
|
|
{
|
|
type Output = Self;
|
|
|
|
fn new(params: &'params ParamsIPA<C>) -> Self {
|
|
AccumulatorStrategy {
|
|
msm: MSMIPA::new(params),
|
|
}
|
|
}
|
|
|
|
fn process(
|
|
mut self,
|
|
f: impl FnOnce(MSMIPA<'params, C>) -> Result<GuardIPA<'params, C>, Error>,
|
|
) -> Result<Self::Output, Error> {
|
|
self.msm.scale(C::Scalar::random(OsRng));
|
|
let guard = f(self.msm)?;
|
|
|
|
Ok(Self {
|
|
msm: guard.use_challenges(),
|
|
})
|
|
}
|
|
|
|
/// 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.
|
|
#[must_use]
|
|
fn finalize(self) -> bool {
|
|
// TODO: Verification is cheap, ZkAccel on verifier is not a priority.
|
|
self.msm.check(&H2cEngine::new())
|
|
}
|
|
}
|
|
|
|
/// A verifier that checks single proof
|
|
#[derive(Debug)]
|
|
pub struct SingleStrategy<'params, C: CurveAffine> {
|
|
msm: MSMIPA<'params, C>,
|
|
}
|
|
|
|
impl<'params, C: CurveAffine> VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<C>>
|
|
for SingleStrategy<'params, C>
|
|
{
|
|
type Output = ();
|
|
|
|
fn new(params: &'params ParamsIPA<C>) -> Self {
|
|
SingleStrategy {
|
|
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)?;
|
|
let msm = guard.use_challenges();
|
|
// ZAL: Verification is (supposedly) cheap, hence we don't use an accelerator engine
|
|
if msm.check(&H2cEngine::new()) {
|
|
Ok(())
|
|
} else {
|
|
Err(Error::ConstraintSystemFailure)
|
|
}
|
|
}
|
|
|
|
/// 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.
|
|
#[must_use]
|
|
fn finalize(self) -> bool {
|
|
unreachable!()
|
|
}
|
|
}
|
|
|
|
/// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} X^{2^i})$.
|
|
fn compute_s<F: Field>(u: &[F], init: F) -> Vec<F> {
|
|
assert!(!u.is_empty());
|
|
let mut v = vec![F::ZERO; 1 << u.len()];
|
|
v[0] = init;
|
|
|
|
for (len, u_j) in u.iter().rev().enumerate().map(|(i, u_j)| (1 << i, u_j)) {
|
|
let (left, right) = v.split_at_mut(len);
|
|
let right = &mut right[0..len];
|
|
right.copy_from_slice(left);
|
|
for v in right {
|
|
*v *= u_j;
|
|
}
|
|
}
|
|
|
|
v
|
|
}
|