diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 00025169ab..65a01873d2 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -88,26 +88,32 @@ pub fn create_proof< return Err(Error::InstanceTooLarge); } for (poly, value) in poly.iter_mut().zip(values.iter()) { + if !P::QUERY_INSTANCE { + transcript.common_scalar(*value)?; + } *poly = *value; } Ok(poly) }) .collect::, _>>()?; - let instance_commitments_projective: Vec<_> = instance_values - .iter() - .map(|poly| params.commit_lagrange(poly, Blind::default())) - .collect(); - let mut instance_commitments = - vec![Scheme::Curve::identity(); instance_commitments_projective.len()]; - ::CurveExt::batch_normalize( - &instance_commitments_projective, - &mut instance_commitments, - ); - let instance_commitments = instance_commitments; - drop(instance_commitments_projective); - - for commitment in &instance_commitments { - transcript.common_point(*commitment)?; + + if P::QUERY_INSTANCE { + let instance_commitments_projective: Vec<_> = instance_values + .iter() + .map(|poly| params.commit_lagrange(poly, Blind::default())) + .collect(); + let mut instance_commitments = + vec![Scheme::Curve::identity(); instance_commitments_projective.len()]; + ::CurveExt::batch_normalize( + &instance_commitments_projective, + &mut instance_commitments, + ); + let instance_commitments = instance_commitments; + drop(instance_commitments_projective); + + for commitment in &instance_commitments { + transcript.common_point(*commitment)?; + } } let instance_polys: Vec<_> = instance_values @@ -504,23 +510,25 @@ pub fn create_proof< let x: ChallengeX<_> = transcript.squeeze_challenge_scalar(); let xn = x.pow(&[params.n() as u64, 0, 0, 0]); - // Compute and hash instance evals for each circuit instance - for instance in instance.iter() { - // Evaluate polynomials at omega^i x - let instance_evals: Vec<_> = meta - .instance_queries - .iter() - .map(|&(column, at)| { - eval_polynomial( - &instance.instance_polys[column.index()], - domain.rotate_omega(*x, at), - ) - }) - .collect(); + if P::QUERY_INSTANCE { + // Compute and hash instance evals for each circuit instance + for instance in instance.iter() { + // Evaluate polynomials at omega^i x + let instance_evals: Vec<_> = meta + .instance_queries + .iter() + .map(|&(column, at)| { + eval_polynomial( + &instance.instance_polys[column.index()], + domain.rotate_omega(*x, at), + ) + }) + .collect(); - // Hash each instance column evaluation - for eval in instance_evals.iter() { - transcript.write_scalar(*eval)?; + // Hash each instance column evaluation + for eval in instance_evals.iter() { + transcript.write_scalar(*eval)?; + } } } @@ -588,15 +596,16 @@ pub fn create_proof< .flat_map(|(((instance, advice), permutation), lookups)| { iter::empty() .chain( - pk.vk - .cs - .instance_queries - .iter() - .map(move |&(column, at)| ProverQuery { - point: domain.rotate_omega(*x, at), - poly: &instance.instance_polys[column.index()], - blind: Blind::default(), - }), + P::QUERY_INSTANCE + .then_some(pk.vk.cs.instance_queries.iter().map(move |&(column, at)| { + ProverQuery { + point: domain.rotate_omega(*x, at), + poly: &instance.instance_polys[column.index()], + blind: Blind::default(), + } + })) + .into_iter() + .flatten(), ) .chain( pk.vk diff --git a/halo2_proofs/src/plonk/verifier.rs b/halo2_proofs/src/plonk/verifier.rs index 0163b9fef3..e6a2327e7b 100644 --- a/halo2_proofs/src/plonk/verifier.rs +++ b/halo2_proofs/src/plonk/verifier.rs @@ -7,7 +7,7 @@ use super::{ vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, VerifyingKey, }; -use crate::arithmetic::{CurveAffine, FieldExt}; +use crate::arithmetic::{compute_inner_product, CurveAffine, FieldExt}; use crate::poly::commitment::{CommitmentScheme, Verifier}; use crate::poly::VerificationStrategy; use crate::poly::{ @@ -45,34 +45,48 @@ pub fn verify_proof< } } - let instance_commitments = instances - .iter() - .map(|instance| { - instance - .iter() - .map(|instance| { - if instance.len() > params.n() as usize - (vk.cs.blinding_factors() + 1) { - return Err(Error::InstanceTooLarge); - } - let mut poly = instance.to_vec(); - poly.resize(params.n() as usize, Scheme::Scalar::zero()); - let poly = vk.domain.lagrange_from_vec(poly); - - Ok(params.commit_lagrange(&poly, Blind::default()).to_affine()) - }) - .collect::, _>>() - }) - .collect::, _>>()?; + let instance_commitments = if V::QUERY_INSTANCE { + instances + .iter() + .map(|instance| { + instance + .iter() + .map(|instance| { + if instance.len() > params.n() as usize - (vk.cs.blinding_factors() + 1) { + return Err(Error::InstanceTooLarge); + } + let mut poly = instance.to_vec(); + poly.resize(params.n() as usize, Scheme::Scalar::zero()); + let poly = vk.domain.lagrange_from_vec(poly); + + Ok(params.commit_lagrange(&poly, Blind::default()).to_affine()) + }) + .collect::, _>>() + }) + .collect::, _>>()? + } else { + vec![vec![]; instances.len()] + }; let num_proofs = instance_commitments.len(); // Hash verification key into transcript vk.hash_into(transcript)?; - for instance_commitments in instance_commitments.iter() { - // Hash the instance (external) commitments into the transcript - for commitment in instance_commitments { - transcript.common_point(*commitment)? + if V::QUERY_INSTANCE { + for instance_commitments in instance_commitments.iter() { + // Hash the instance (external) commitments into the transcript + for commitment in instance_commitments { + transcript.common_point(*commitment)? + } + } + } else { + for instance in instances.iter() { + for instance in instance.iter() { + for value in instance.iter() { + transcript.common_scalar(*value)?; + } + } } } @@ -153,9 +167,52 @@ pub fn verify_proof< // Sample x challenge, which is used to ensure the circuit is // satisfied with high probability. let x: ChallengeX<_> = transcript.squeeze_challenge_scalar(); - let instance_evals = (0..num_proofs) - .map(|_| -> Result, _> { read_n_scalars(transcript, vk.cs.instance_queries.len()) }) - .collect::, _>>()?; + let instance_evals = if V::QUERY_INSTANCE { + (0..num_proofs) + .map(|_| -> Result, _> { + read_n_scalars(transcript, vk.cs.instance_queries.len()) + }) + .collect::, _>>()? + } else { + let xn = x.pow(&[params.n() as u64, 0, 0, 0]); + let (min_rotation, max_rotation) = + vk.cs + .instance_queries + .iter() + .fold((0, 0), |(min, max), (_, rotation)| { + if rotation.0 < min { + (rotation.0, max) + } else if rotation.0 > max { + (min, rotation.0) + } else { + (min, max) + } + }); + let max_instance_len = instances + .iter() + .flat_map(|instance| instance.iter().map(|instance| instance.len())) + .max_by(Ord::cmp) + .unwrap_or_default(); + let l_i_s = &vk.domain.l_i_range( + *x, + xn, + -max_rotation..max_instance_len as i32 + min_rotation.abs(), + ); + instances + .iter() + .map(|instances| { + vk.cs + .instance_queries + .iter() + .map(|(column, rotation)| { + let instances = instances[column.index()]; + let offset = (max_rotation - rotation.0) as usize; + compute_inner_product(instances, &l_i_s[offset..offset + instances.len()]) + }) + .collect::>() + }) + .collect::>() + }; let advice_evals = (0..num_proofs) .map(|_| -> Result, _> { read_n_scalars(transcript, vk.cs.advice_queries.len()) }) @@ -282,15 +339,20 @@ pub fn verify_proof< lookups, )| { iter::empty() - .chain(vk.cs.instance_queries.iter().enumerate().map( - move |(query_index, &(column, at))| { - VerifierQuery::new_commitment( - &instance_commitments[column.index()], - vk.domain.rotate_omega(*x, at), - instance_evals[query_index], - ) - }, - )) + .chain( + V::QUERY_INSTANCE + .then_some(vk.cs.instance_queries.iter().enumerate().map( + move |(query_index, &(column, at))| { + VerifierQuery::new_commitment( + &instance_commitments[column.index()], + vk.domain.rotate_omega(*x, at), + instance_evals[query_index], + ) + }, + )) + .into_iter() + .flatten(), + ) .chain(vk.cs.advice_queries.iter().enumerate().map( move |(query_index, &(column, at))| { VerifierQuery::new_commitment( diff --git a/halo2_proofs/src/poly/commitment.rs b/halo2_proofs/src/poly/commitment.rs index ef336d595f..91fa244280 100644 --- a/halo2_proofs/src/poly/commitment.rs +++ b/halo2_proofs/src/poly/commitment.rs @@ -126,6 +126,9 @@ pub trait MSM: Clone + Debug { /// Common multi-open prover interface for various commitment schemes pub trait Prover<'params, Scheme: CommitmentScheme> { + /// Query instance or not + const QUERY_INSTANCE: bool; + /// Creates new prover instance fn new(params: &'params Scheme::ParamsProver) -> Self; @@ -156,6 +159,9 @@ pub trait Verifier<'params, Scheme: CommitmentScheme> { /// Accumulator fot comressed verification type MSMAccumulator; + /// Query instance or not + const QUERY_INSTANCE: bool; + /// Creates new verifier instance fn new(params: &'params Scheme::ParamsVerifier) -> Self; diff --git a/halo2_proofs/src/poly/ipa/multiopen/prover.rs b/halo2_proofs/src/poly/ipa/multiopen/prover.rs index e01b9d17d4..bba038c93a 100644 --- a/halo2_proofs/src/poly/ipa/multiopen/prover.rs +++ b/halo2_proofs/src/poly/ipa/multiopen/prover.rs @@ -22,6 +22,8 @@ pub struct ProverIPA<'params, C: CurveAffine> { } impl<'params, C: CurveAffine> Prover<'params, IPACommitmentScheme> for ProverIPA<'params, C> { + const QUERY_INSTANCE: bool = true; + fn new(params: &'params ParamsIPA) -> Self { Self { params } } diff --git a/halo2_proofs/src/poly/ipa/multiopen/verifier.rs b/halo2_proofs/src/poly/ipa/multiopen/verifier.rs index 1c840b6de7..ff4c7626f6 100644 --- a/halo2_proofs/src/poly/ipa/multiopen/verifier.rs +++ b/halo2_proofs/src/poly/ipa/multiopen/verifier.rs @@ -30,6 +30,8 @@ impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme> type Guard = GuardIPA<'params, C>; type MSMAccumulator = MSMIPA<'params, C>; + const QUERY_INSTANCE: bool = true; + fn new(params: &'params ParamsVerifierIPA) -> Self { Self { params } } diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs index e3575b390c..e5077b1b58 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs @@ -28,6 +28,8 @@ pub struct ProverGWC<'params, E: Engine> { /// Create a multi-opening proof impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverGWC<'params, E> { + const QUERY_INSTANCE: bool = false; + fn new(params: &'params ParamsKZG) -> Self { Self { params } } diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs index e5218d36ef..8f9d348942 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs @@ -36,6 +36,8 @@ impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme< type Guard = GuardKZG<'params, E>; type MSMAccumulator = DualMSM<'params, E>; + const QUERY_INSTANCE: bool = false; + fn new(params: &'params ParamsKZG) -> Self { Self { params } } diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs index e99e0b91ea..2585d9ab69 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs @@ -104,6 +104,8 @@ impl<'a, E: Engine> ProverSHPLONK<'a, E> { impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverSHPLONK<'params, E> { + const QUERY_INSTANCE: bool = false; + fn new(params: &'params ParamsKZG) -> Self { Self { params } } diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs index 5438d41481..75626d74c6 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs @@ -39,6 +39,8 @@ impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme< type Guard = GuardKZG<'params, E>; type MSMAccumulator = DualMSM<'params, E>; + const QUERY_INSTANCE: bool = false; + fn new(params: &'params ParamsKZG) -> Self { Self { params } }