Refactor PLONK verifier

This commit is contained in:
therealyingtong 2021-01-21 08:04:44 +08:00
parent 02b5b8442b
commit def65609b1
1 changed files with 184 additions and 124 deletions

View File

@ -17,28 +17,40 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
params: &'a Params<C>, params: &'a Params<C>,
vk: &VerifyingKey<C>, vk: &VerifyingKey<C>,
msm: MSM<'a, C>, msm: MSM<'a, C>,
aux_commitments: &[C], aux_commitments_vec: &[&[C]],
transcript: &mut T, transcript: &mut T,
) -> Result<Guard<'a, C>, Error> { ) -> Result<Guard<'a, C>, Error> {
// Check that aux_commitments matches the expected number of aux columns // Check that aux_commitments matches the expected number of aux columns
for aux_commitments in aux_commitments_vec.iter() {
if aux_commitments.len() != vk.cs.num_aux_columns { if aux_commitments.len() != vk.cs.num_aux_columns {
return Err(Error::IncompatibleParams); return Err(Error::IncompatibleParams);
} }
}
let num_proofs = aux_commitments_vec.len();
for aux_commitments in aux_commitments_vec.iter() {
// Hash the aux (external) commitments into the transcript // Hash the aux (external) commitments into the transcript
for commitment in aux_commitments { for commitment in *aux_commitments {
transcript transcript
.common_point(*commitment) .common_point(*commitment)
.map_err(|_| Error::TranscriptError)? .map_err(|_| Error::TranscriptError)?
} }
}
let mut advice_commitments_vec = Vec::with_capacity(num_proofs);
for _ in 0..num_proofs {
// Hash the prover's advice commitments into the transcript // Hash the prover's advice commitments into the transcript
let advice_commitments = let advice_commitments = read_n_points(transcript, vk.cs.num_advice_columns)
read_n_points(transcript, vk.cs.num_advice_columns).map_err(|_| Error::TranscriptError)?; .map_err(|_| Error::TranscriptError)?;
advice_commitments_vec.push(advice_commitments);
}
// Sample theta challenge for keeping lookup columns linearly independent // Sample theta challenge for keeping lookup columns linearly independent
let theta = ChallengeTheta::get(transcript); let theta = ChallengeTheta::get(transcript);
let mut lookups_permuted_vec = Vec::with_capacity(num_proofs);
for _ in 0..num_proofs {
// Hash each lookup permuted commitment // Hash each lookup permuted commitment
let lookups = vk let lookups = vk
.cs .cs
@ -46,6 +58,8 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
.iter() .iter()
.map(|argument| argument.read_permuted_commitments(transcript)) .map(|argument| argument.read_permuted_commitments(transcript))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
lookups_permuted_vec.push(lookups);
}
// Sample beta challenge // Sample beta challenge
let beta = ChallengeBeta::get(transcript); let beta = ChallengeBeta::get(transcript);
@ -53,6 +67,8 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
// Sample gamma challenge // Sample gamma challenge
let gamma = ChallengeGamma::get(transcript); let gamma = ChallengeGamma::get(transcript);
let mut permutations_committed_vec = Vec::with_capacity(num_proofs);
for _ in 0..num_proofs {
// Hash each permutation product commitment // Hash each permutation product commitment
let permutations = vk let permutations = vk
.cs .cs
@ -60,12 +76,18 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
.iter() .iter()
.map(|argument| argument.read_product_commitment(transcript)) .map(|argument| argument.read_product_commitment(transcript))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
permutations_committed_vec.push(permutations);
}
let mut lookups_committed_vec = Vec::with_capacity(num_proofs);
for lookups in lookups_permuted_vec.into_iter() {
// Hash each lookup product commitment // Hash each lookup product commitment
let lookups = lookups let lookups = lookups
.into_iter() .into_iter()
.map(|lookup| lookup.read_product_commitment(transcript)) .map(|lookup| lookup.read_product_commitment(transcript))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
lookups_committed_vec.push(lookups);
}
// Sample y challenge, which keeps the gates linearly independent. // Sample y challenge, which keeps the gates linearly independent.
let y = ChallengeY::get(transcript); let y = ChallengeY::get(transcript);
@ -76,25 +98,43 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
// satisfied with high probability. // satisfied with high probability.
let x = ChallengeX::get(transcript); let x = ChallengeX::get(transcript);
let mut aux_evals_vec = Vec::with_capacity(num_proofs);
for _ in 0..num_proofs {
let aux_evals = read_n_scalars(transcript, vk.cs.aux_queries.len())
.map_err(|_| Error::TranscriptError)?;
aux_evals_vec.push(aux_evals);
}
let mut advice_evals_vec = Vec::with_capacity(num_proofs);
for _ in 0..num_proofs {
let advice_evals = read_n_scalars(transcript, vk.cs.advice_queries.len()) let advice_evals = read_n_scalars(transcript, vk.cs.advice_queries.len())
.map_err(|_| Error::TranscriptError)?; .map_err(|_| Error::TranscriptError)?;
let aux_evals = advice_evals_vec.push(advice_evals);
read_n_scalars(transcript, vk.cs.aux_queries.len()).map_err(|_| Error::TranscriptError)?; }
let fixed_evals = read_n_scalars(transcript, vk.cs.fixed_queries.len()) let fixed_evals = read_n_scalars(transcript, vk.cs.fixed_queries.len())
.map_err(|_| Error::TranscriptError)?; .map_err(|_| Error::TranscriptError)?;
let vanishing = vanishing.evaluate(transcript)?; let vanishing = vanishing.evaluate(transcript)?;
let mut permutations_evaluated_vec = Vec::with_capacity(num_proofs);
for permutations in permutations_committed_vec.into_iter() {
let permutations = permutations let permutations = permutations
.into_iter() .into_iter()
.zip(vk.permutations.iter()) .zip(vk.permutations.iter())
.map(|(permutation, vkey)| permutation.evaluate(vkey, transcript)) .map(|(permutation, vkey)| permutation.evaluate(vkey, transcript))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
permutations_evaluated_vec.push(permutations);
}
let mut lookups_evaluated_vec = Vec::with_capacity(num_proofs);
for lookups in lookups_committed_vec.into_iter() {
let lookups = lookups let lookups = lookups
.into_iter() .into_iter()
.map(|lookup| lookup.evaluate(transcript)) .map(|lookup| lookup.evaluate(transcript))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
lookups_evaluated_vec.push(lookups);
}
// This check ensures the circuit is satisfied so long as the polynomial // This check ensures the circuit is satisfied so long as the polynomial
// commitments open to the correct values. // commitments open to the correct values.
@ -109,9 +149,18 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
* &vk.domain.get_barycentric_weight(); // l_0(x) * &vk.domain.get_barycentric_weight(); // l_0(x)
// Compute the expected value of h(x) // Compute the expected value of h(x)
let expressions = std::iter::empty() let expressions = advice_evals_vec
.iter()
.zip(aux_evals_vec.iter())
.zip(permutations_evaluated_vec.iter())
.zip(lookups_evaluated_vec.iter())
.flat_map(|(((advice_evals, aux_evals), permutations), lookups)| {
let fixed_evals = fixed_evals.clone();
let fixed_evals_copy = fixed_evals.clone();
std::iter::empty()
// Evaluate the circuit using the custom gates provided // Evaluate the circuit using the custom gates provided
.chain(vk.cs.gates.iter().map(|poly| { .chain(vk.cs.gates.iter().map(move |poly| {
poly.evaluate( poly.evaluate(
&|index| fixed_evals[index], &|index| fixed_evals[index],
&|index| advice_evals[index], &|index| advice_evals[index],
@ -125,7 +174,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
permutations permutations
.iter() .iter()
.zip(vk.cs.permutations.iter()) .zip(vk.cs.permutations.iter())
.map(|(p, argument)| { .map(move |(p, argument)| {
p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x) p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x)
}) })
.into_iter() .into_iter()
@ -135,7 +184,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
lookups lookups
.iter() .iter()
.zip(vk.cs.lookups.iter()) .zip(vk.cs.lookups.iter())
.map(|(p, argument)| { .map(move |(p, argument)| {
p.expressions( p.expressions(
vk, vk,
l_0, l_0,
@ -144,67 +193,78 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
beta, beta,
gamma, gamma,
&advice_evals, &advice_evals,
&fixed_evals, &fixed_evals_copy,
&aux_evals, &aux_evals,
) )
}) })
.into_iter() .into_iter()
.flatten(), .flatten(),
); )
})
.collect::<Vec<_>>()
.into_iter();
vanishing.verify(expressions, y, xn)?; vanishing.verify(expressions, y, xn)?;
} }
let queries = iter::empty() let queries = aux_commitments_vec
.chain(
vk.cs
.advice_queries
.iter() .iter()
.enumerate() .zip(aux_evals_vec.iter())
.map(|(query_index, &(column, at))| VerifierQuery { .zip(advice_commitments_vec.iter())
point: vk.domain.rotate_omega(*x, at), .zip(advice_evals_vec.iter())
commitment: &advice_commitments[column.index()], .zip(permutations_evaluated_vec.iter())
eval: advice_evals[query_index], .zip(lookups_evaluated_vec.iter())
}), .flat_map(
) |(
.chain( ((((aux_commitments, aux_evals), advice_commitments), advice_evals), permutations),
vk.cs lookups,
.aux_queries )| {
.iter() iter::empty()
.enumerate() .chain(vk.cs.aux_queries.iter().enumerate().map(
.map(|(query_index, &(column, at))| VerifierQuery { move |(query_index, &(column, at))| VerifierQuery {
point: vk.domain.rotate_omega(*x, at), point: vk.domain.rotate_omega(*x, at),
commitment: &aux_commitments[column.index()], commitment: &aux_commitments[column.index()],
eval: aux_evals[query_index], eval: aux_evals[query_index],
}), },
) ))
.chain( .chain(vk.cs.advice_queries.iter().enumerate().map(
vk.cs move |(query_index, &(column, at))| VerifierQuery {
.fixed_queries
.iter()
.enumerate()
.map(|(query_index, &(column, at))| VerifierQuery {
point: vk.domain.rotate_omega(*x, at), point: vk.domain.rotate_omega(*x, at),
commitment: &vk.fixed_commitments[column.index()], commitment: &advice_commitments[column.index()],
eval: fixed_evals[query_index], eval: advice_evals[query_index],
}), },
) ))
.chain(vanishing.queries(x))
.chain( .chain(
permutations permutations
.iter() .iter()
.zip(vk.permutations.iter()) .zip(vk.permutations.iter())
.map(|(p, vkey)| p.queries(vk, vkey, x)) .map(move |(p, vkey)| p.queries(vk, vkey, x))
.into_iter() .into_iter()
.flatten(), .flatten(),
) )
.chain( .chain(
lookups lookups
.iter() .iter()
.map(|p| p.queries(vk, x)) .map(move |p| p.queries(vk, x))
.into_iter() .into_iter()
.flatten(), .flatten(),
); )
},
)
.collect::<Vec<_>>()
.into_iter()
.chain(
vk.cs
.fixed_queries
.iter()
.enumerate()
.map(move |(query_index, &(column, at))| VerifierQuery {
point: vk.domain.rotate_omega(*x, at),
commitment: &vk.fixed_commitments[column.index()],
eval: fixed_evals.clone()[query_index],
}),
)
.chain(vanishing.queries(x));
// We are now convinced the circuit is satisfied so long as the // We are now convinced the circuit is satisfied so long as the
// polynomial commitments open to the correct values. // polynomial commitments open to the correct values.