2020-11-13 00:08:08 +00:00
|
|
|
use ff::Field;
|
2020-10-21 16:10:57 +00:00
|
|
|
use std::iter;
|
|
|
|
|
|
2020-12-01 06:44:14 +00:00
|
|
|
use super::{
|
2020-12-23 20:03:31 +00:00
|
|
|
vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error,
|
2020-12-01 06:44:14 +00:00
|
|
|
VerifyingKey,
|
|
|
|
|
};
|
2020-11-25 19:26:31 +00:00
|
|
|
use crate::arithmetic::{CurveAffine, FieldExt};
|
2020-09-09 13:00:36 +00:00
|
|
|
use crate::poly::{
|
2020-09-15 23:32:39 +00:00
|
|
|
commitment::{Guard, Params, MSM},
|
2020-12-23 20:03:31 +00:00
|
|
|
multiopen::{self, VerifierQuery},
|
2020-09-09 13:00:36 +00:00
|
|
|
};
|
2020-12-23 20:03:31 +00:00
|
|
|
use crate::transcript::{read_n_points, read_n_scalars, TranscriptRead};
|
|
|
|
|
|
|
|
|
|
/// Returns a boolean indicating whether or not the proof is valid
|
2020-12-23 23:20:27 +00:00
|
|
|
pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
|
2020-12-23 20:03:31 +00:00
|
|
|
params: &'a Params<C>,
|
2020-12-23 22:34:07 +00:00
|
|
|
vk: &VerifyingKey<C>,
|
2020-12-23 20:03:31 +00:00
|
|
|
msm: MSM<'a, C>,
|
2021-01-31 03:42:16 +00:00
|
|
|
aux_commitments: &[&[C]],
|
2020-12-23 20:03:31 +00:00
|
|
|
transcript: &mut T,
|
|
|
|
|
) -> Result<Guard<'a, C>, Error> {
|
|
|
|
|
// Check that aux_commitments matches the expected number of aux columns
|
2021-01-31 03:42:16 +00:00
|
|
|
for aux_commitments in aux_commitments.iter() {
|
2021-01-21 00:04:44 +00:00
|
|
|
if aux_commitments.len() != vk.cs.num_aux_columns {
|
|
|
|
|
return Err(Error::IncompatibleParams);
|
|
|
|
|
}
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|
2020-09-29 22:56:21 +00:00
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let num_proofs = aux_commitments.len();
|
2021-01-21 00:04:44 +00:00
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
for aux_commitments in aux_commitments.iter() {
|
2021-01-21 00:04:44 +00:00
|
|
|
// Hash the aux (external) commitments into the transcript
|
|
|
|
|
for commitment in *aux_commitments {
|
|
|
|
|
transcript
|
|
|
|
|
.common_point(*commitment)
|
|
|
|
|
.map_err(|_| Error::TranscriptError)?
|
|
|
|
|
}
|
2020-09-29 23:35:24 +00:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let advice_commitments = (0..num_proofs)
|
2021-01-26 07:23:29 +00:00
|
|
|
.map(|_| -> Result<Vec<_>, _> {
|
|
|
|
|
// Hash the prover's advice commitments into the transcript
|
|
|
|
|
read_n_points(transcript, vk.cs.num_advice_columns).map_err(|_| Error::TranscriptError)
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
|
|
|
|
// Sample theta challenge for keeping lookup columns linearly independent
|
|
|
|
|
let theta = ChallengeTheta::get(transcript);
|
|
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let lookups_permuted = (0..num_proofs)
|
2021-01-26 07:23:29 +00:00
|
|
|
.map(|_| -> Result<Vec<_>, _> {
|
|
|
|
|
// Hash each lookup permuted commitment
|
|
|
|
|
vk.cs
|
|
|
|
|
.lookups
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|argument| argument.read_permuted_commitments(transcript))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
|
|
|
|
// Sample beta challenge
|
|
|
|
|
let beta = ChallengeBeta::get(transcript);
|
|
|
|
|
|
|
|
|
|
// Sample gamma challenge
|
|
|
|
|
let gamma = ChallengeGamma::get(transcript);
|
|
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let permutations_committed = (0..num_proofs)
|
2021-01-26 07:23:29 +00:00
|
|
|
.map(|_| -> Result<Vec<_>, _> {
|
|
|
|
|
// Hash each permutation product commitment
|
|
|
|
|
vk.cs
|
|
|
|
|
.permutations
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|argument| argument.read_product_commitment(transcript))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let lookups_committed = lookups_permuted
|
2021-01-26 07:23:29 +00:00
|
|
|
.into_iter()
|
|
|
|
|
.map(|lookups| {
|
|
|
|
|
// Hash each lookup product commitment
|
|
|
|
|
lookups
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|lookup| lookup.read_product_commitment(transcript))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
|
|
|
|
// Sample y challenge, which keeps the gates linearly independent.
|
|
|
|
|
let y = ChallengeY::get(transcript);
|
|
|
|
|
|
2021-01-13 22:47:35 +00:00
|
|
|
let vanishing = vanishing::Argument::read_commitments(vk, transcript)?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
|
|
|
|
// Sample x challenge, which is used to ensure the circuit is
|
|
|
|
|
// satisfied with high probability.
|
|
|
|
|
let x = ChallengeX::get(transcript);
|
|
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let aux_evals = (0..num_proofs)
|
2021-01-26 07:23:29 +00:00
|
|
|
.map(|_| -> Result<Vec<_>, _> {
|
|
|
|
|
read_n_scalars(transcript, vk.cs.aux_queries.len()).map_err(|_| Error::TranscriptError)
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2021-01-21 00:04:44 +00:00
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let advice_evals = (0..num_proofs)
|
2021-01-26 07:23:29 +00:00
|
|
|
.map(|_| -> Result<Vec<_>, _> {
|
|
|
|
|
read_n_scalars(transcript, vk.cs.advice_queries.len())
|
|
|
|
|
.map_err(|_| Error::TranscriptError)
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2021-01-21 00:04:44 +00:00
|
|
|
|
2020-12-23 20:03:31 +00:00
|
|
|
let fixed_evals = read_n_scalars(transcript, vk.cs.fixed_queries.len())
|
|
|
|
|
.map_err(|_| Error::TranscriptError)?;
|
|
|
|
|
|
|
|
|
|
let vanishing = vanishing.evaluate(transcript)?;
|
|
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let permutations_evaluated = permutations_committed
|
2021-01-26 07:23:29 +00:00
|
|
|
.into_iter()
|
|
|
|
|
.map(|permutations| -> Result<Vec<_>, _> {
|
|
|
|
|
permutations
|
|
|
|
|
.into_iter()
|
|
|
|
|
.zip(vk.permutations.iter())
|
|
|
|
|
.map(|(permutation, vkey)| permutation.evaluate(vkey, transcript))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let lookups_evaluated = lookups_committed
|
2021-01-26 07:23:29 +00:00
|
|
|
.into_iter()
|
|
|
|
|
.map(|lookups| -> Result<Vec<_>, _> {
|
|
|
|
|
lookups
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|lookup| lookup.evaluate(transcript))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
2020-12-23 20:03:31 +00:00
|
|
|
|
|
|
|
|
// This check ensures the circuit is satisfied so long as the polynomial
|
|
|
|
|
// commitments open to the correct values.
|
|
|
|
|
{
|
2020-11-25 19:26:31 +00:00
|
|
|
// x^n
|
|
|
|
|
let xn = x.pow(&[params.n as u64, 0, 0, 0]);
|
2020-09-29 22:56:21 +00:00
|
|
|
|
|
|
|
|
// TODO: bubble this error up
|
2020-11-25 19:26:31 +00:00
|
|
|
// l_0(x)
|
|
|
|
|
let l_0 = (*x - &C::Scalar::one()).invert().unwrap() // 1 / (x - 1)
|
|
|
|
|
* &(xn - &C::Scalar::one()) // (x^n - 1) / (x - 1)
|
|
|
|
|
* &vk.domain.get_barycentric_weight(); // l_0(x)
|
2020-09-29 22:56:21 +00:00
|
|
|
|
2020-11-25 19:26:31 +00:00
|
|
|
// Compute the expected value of h(x)
|
2021-01-31 03:42:16 +00:00
|
|
|
let expressions = advice_evals
|
2021-01-21 00:04:44 +00:00
|
|
|
.iter()
|
2021-01-31 03:42:16 +00:00
|
|
|
.zip(aux_evals.iter())
|
|
|
|
|
.zip(permutations_evaluated.iter())
|
|
|
|
|
.zip(lookups_evaluated.iter())
|
2021-01-21 00:04:44 +00:00
|
|
|
.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
|
|
|
|
|
.chain(vk.cs.gates.iter().map(move |poly| {
|
|
|
|
|
poly.evaluate(
|
|
|
|
|
&|index| fixed_evals[index],
|
|
|
|
|
&|index| advice_evals[index],
|
|
|
|
|
&|index| aux_evals[index],
|
|
|
|
|
&|a, b| a + &b,
|
|
|
|
|
&|a, b| a * &b,
|
|
|
|
|
&|a, scalar| a * &scalar,
|
2020-12-01 19:00:59 +00:00
|
|
|
)
|
2021-01-21 00:04:44 +00:00
|
|
|
}))
|
|
|
|
|
.chain(
|
|
|
|
|
permutations
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(vk.cs.permutations.iter())
|
2021-01-26 07:23:29 +00:00
|
|
|
.flat_map(move |(p, argument)| {
|
2021-01-21 00:04:44 +00:00
|
|
|
p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x)
|
|
|
|
|
})
|
2021-01-26 07:23:29 +00:00
|
|
|
.into_iter(),
|
2021-01-21 00:04:44 +00:00
|
|
|
)
|
|
|
|
|
.chain(
|
|
|
|
|
lookups
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(vk.cs.lookups.iter())
|
2021-01-26 07:23:29 +00:00
|
|
|
.flat_map(move |(p, argument)| {
|
2021-01-21 00:04:44 +00:00
|
|
|
p.expressions(
|
|
|
|
|
vk,
|
|
|
|
|
l_0,
|
|
|
|
|
argument,
|
|
|
|
|
theta,
|
|
|
|
|
beta,
|
|
|
|
|
gamma,
|
|
|
|
|
&advice_evals,
|
|
|
|
|
&fixed_evals_copy,
|
|
|
|
|
&aux_evals,
|
|
|
|
|
)
|
|
|
|
|
})
|
2021-01-26 07:23:29 +00:00
|
|
|
.into_iter(),
|
2021-01-21 00:04:44 +00:00
|
|
|
)
|
2021-01-26 07:23:29 +00:00
|
|
|
});
|
2020-09-29 22:56:21 +00:00
|
|
|
|
2020-12-23 20:03:31 +00:00
|
|
|
vanishing.verify(expressions, y, xn)?;
|
2020-09-29 22:56:21 +00:00
|
|
|
}
|
2020-12-23 20:03:31 +00:00
|
|
|
|
2021-01-31 03:42:16 +00:00
|
|
|
let queries = aux_commitments
|
2021-01-21 00:04:44 +00:00
|
|
|
.iter()
|
2021-01-31 03:42:16 +00:00
|
|
|
.zip(aux_evals.iter())
|
|
|
|
|
.zip(advice_commitments.iter())
|
|
|
|
|
.zip(advice_evals.iter())
|
|
|
|
|
.zip(permutations_evaluated.iter())
|
|
|
|
|
.zip(lookups_evaluated.iter())
|
2021-01-21 00:04:44 +00:00
|
|
|
.flat_map(
|
|
|
|
|
|(
|
|
|
|
|
((((aux_commitments, aux_evals), advice_commitments), advice_evals), permutations),
|
|
|
|
|
lookups,
|
|
|
|
|
)| {
|
|
|
|
|
iter::empty()
|
|
|
|
|
.chain(vk.cs.aux_queries.iter().enumerate().map(
|
|
|
|
|
move |(query_index, &(column, at))| VerifierQuery {
|
|
|
|
|
point: vk.domain.rotate_omega(*x, at),
|
|
|
|
|
commitment: &aux_commitments[column.index()],
|
|
|
|
|
eval: aux_evals[query_index],
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
.chain(vk.cs.advice_queries.iter().enumerate().map(
|
|
|
|
|
move |(query_index, &(column, at))| VerifierQuery {
|
|
|
|
|
point: vk.domain.rotate_omega(*x, at),
|
|
|
|
|
commitment: &advice_commitments[column.index()],
|
|
|
|
|
eval: advice_evals[query_index],
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
.chain(
|
|
|
|
|
permutations
|
|
|
|
|
.iter()
|
|
|
|
|
.zip(vk.permutations.iter())
|
2021-01-26 07:23:29 +00:00
|
|
|
.flat_map(move |(p, vkey)| p.queries(vk, vkey, x))
|
|
|
|
|
.into_iter(),
|
2021-01-21 00:04:44 +00:00
|
|
|
)
|
|
|
|
|
.chain(
|
|
|
|
|
lookups
|
|
|
|
|
.iter()
|
2021-01-26 07:23:29 +00:00
|
|
|
.flat_map(move |p| p.queries(vk, x))
|
|
|
|
|
.into_iter(),
|
2021-01-21 00:04:44 +00:00
|
|
|
)
|
|
|
|
|
},
|
2020-12-23 20:03:31 +00:00
|
|
|
)
|
|
|
|
|
.chain(
|
|
|
|
|
vk.cs
|
|
|
|
|
.fixed_queries
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
2021-01-31 03:42:16 +00:00
|
|
|
.map(|(query_index, &(column, at))| VerifierQuery {
|
2020-12-23 20:03:31 +00:00
|
|
|
point: vk.domain.rotate_omega(*x, at),
|
|
|
|
|
commitment: &vk.fixed_commitments[column.index()],
|
2021-01-31 03:42:16 +00:00
|
|
|
eval: fixed_evals[query_index],
|
2020-12-23 20:03:31 +00:00
|
|
|
}),
|
|
|
|
|
)
|
2021-01-21 00:04:44 +00:00
|
|
|
.chain(vanishing.queries(x));
|
2020-12-23 20:03:31 +00:00
|
|
|
|
|
|
|
|
// We are now convinced the circuit is satisfied so long as the
|
|
|
|
|
// polynomial commitments open to the correct values.
|
|
|
|
|
multiopen::verify_proof(params, transcript, queries, msm).map_err(|_| Error::OpeningError)
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|