plonky2/src/prover.rs

385 lines
14 KiB
Rust
Raw Normal View History

2021-03-25 15:20:14 -07:00
use std::time::Instant;
use log::info;
use rayon::prelude::*;
2021-03-25 15:20:14 -07:00
2021-03-30 13:30:31 -07:00
use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
2021-05-18 15:22:06 +02:00
use crate::field::extension_field::Extendable;
2021-03-21 11:17:00 -07:00
use crate::generator::generate_partial_witness;
use crate::plonk_challenger::Challenger;
2021-06-25 11:49:29 +02:00
use crate::plonk_common::{eval_vanishing_poly_base, PlonkPolynomials, ZeroPolyOnCoset};
2021-05-18 16:06:47 +02:00
use crate::polynomial::commitment::ListPolynomialCommitment;
2021-06-24 11:45:16 +02:00
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
2021-05-10 13:10:40 +02:00
use crate::proof::Proof;
use crate::timed;
use crate::util::partial_products::partial_products;
2021-07-02 11:01:20 +02:00
use crate::util::{log2_ceil, transpose};
use crate::vars::EvaluationVarsBase;
use crate::witness::{PartialWitness, Witness};
2021-02-09 21:25:21 -08:00
pub(crate) fn prove<F: Extendable<D>, const D: usize>(
prover_data: &ProverOnlyCircuitData<F, D>,
common_data: &CommonCircuitData<F, D>,
2021-03-21 11:17:00 -07:00
inputs: PartialWitness<F>,
2021-05-18 15:44:50 +02:00
) -> Proof<F, D> {
2021-05-07 11:30:03 +02:00
let fri_config = &common_data.config.fri_config;
let config = &common_data.config;
let num_wires = config.num_wires;
let num_challenges = config.num_challenges;
let quotient_degree = common_data.quotient_degree();
let degree = common_data.degree();
2021-05-07 11:30:03 +02:00
2021-03-30 23:47:29 -07:00
let start_proof_gen = Instant::now();
let mut partial_witness = inputs;
2021-03-25 15:20:14 -07:00
info!("Running {} generators", prover_data.generators.len());
2021-05-07 11:30:03 +02:00
timed!(
generate_partial_witness(&mut partial_witness, &prover_data.generators),
2021-05-07 11:30:03 +02:00
"to generate witness"
2021-04-21 22:31:45 +02:00
);
2021-03-21 11:17:00 -07:00
let witness = timed!(
partial_witness.full_witness(degree, num_wires),
"to compute full witness"
);
timed!(
witness
.check_copy_constraints(&prover_data.copy_constraints, &prover_data.gate_instances)
.unwrap(), // TODO: Change return value to `Result` and use `?` here.
"to check copy constraints"
);
let wires_values: Vec<PolynomialValues<F>> = timed!(
witness
.wire_values
.iter()
.map(|column| PolynomialValues::new(column.clone()))
2021-05-07 11:30:03 +02:00
.collect(),
"to compute wire polynomials"
2021-04-21 22:31:45 +02:00
);
2021-03-25 15:20:14 -07:00
2021-03-30 10:02:00 -07:00
// TODO: Could try parallelizing the transpose, or not doing it explicitly, instead having
// merkle_root_bit_rev_order do it implicitly.
2021-05-07 11:30:03 +02:00
let wires_commitment = timed!(
2021-06-25 11:49:29 +02:00
ListPolynomialCommitment::new(
wires_values,
fri_config.rate_bits,
PlonkPolynomials::WIRES.blinding
),
2021-05-07 11:30:03 +02:00
"to compute wires commitment"
2021-04-21 22:31:45 +02:00
);
2021-03-21 11:57:33 -07:00
2021-03-31 21:15:24 -07:00
let mut challenger = Challenger::new();
// Observe the instance.
// TODO: Need to include public inputs as well.
challenger.observe_hash(&common_data.circuit_digest);
2021-05-06 23:14:37 +02:00
challenger.observe_hash(&wires_commitment.merkle_tree.root);
2021-05-14 08:07:00 -07:00
let betas = challenger.get_n_challenges(num_challenges);
let gammas = challenger.get_n_challenges(num_challenges);
2021-03-31 21:15:24 -07:00
2021-07-02 10:58:59 +02:00
assert!(
common_data.max_filtered_constraint_degree<=common_data.config.num_routed_wires,
"When the number of routed wires is smaller that the degree, we should change the logic to avoid computing partial products."
);
2021-07-01 15:20:16 +02:00
let mut partial_products = timed!(
2021-06-30 15:05:40 +02:00
all_wires_permutation_partial_products(&witness, &betas, &gammas, prover_data, common_data),
"to compute partial products"
);
2021-07-01 17:28:30 +02:00
let plonk_z_vecs = timed!(compute_zs(&partial_products, common_data), "to compute Z's");
2021-03-30 23:47:29 -07:00
2021-07-01 17:28:30 +02:00
// The first two polynomials in `partial_products` represent the final products used in the
// computation of `Z`. They aren't needed anymore so we discard them.
2021-07-01 15:20:16 +02:00
partial_products.iter_mut().for_each(|part| {
part.drain(0..2);
});
2021-06-30 18:54:28 +02:00
let zs_partial_products = [plonk_z_vecs, partial_products.concat()].concat();
2021-07-01 17:28:30 +02:00
let zs_partial_products_commitment = timed!(
2021-06-25 11:49:29 +02:00
ListPolynomialCommitment::new(
2021-06-30 18:54:28 +02:00
zs_partial_products,
2021-06-25 11:49:29 +02:00
fri_config.rate_bits,
2021-07-01 17:34:00 +02:00
PlonkPolynomials::ZS_PARTIAL_PRODUCTS.blinding
2021-06-25 11:49:29 +02:00
),
2021-05-07 11:30:03 +02:00
"to commit to Z's"
2021-04-21 22:31:45 +02:00
);
2021-07-01 17:28:30 +02:00
challenger.observe_hash(&zs_partial_products_commitment.merkle_tree.root);
2021-03-31 21:15:24 -07:00
2021-05-14 08:07:00 -07:00
let alphas = challenger.get_n_challenges(num_challenges);
2021-03-31 21:15:24 -07:00
2021-06-24 11:45:16 +02:00
let quotient_polys = timed!(
compute_quotient_polys(
2021-05-07 11:30:03 +02:00
common_data,
prover_data,
2021-05-07 16:22:13 +02:00
&wires_commitment,
2021-07-01 17:28:30 +02:00
&zs_partial_products_commitment,
2021-05-07 11:30:03 +02:00
&betas,
&gammas,
&alphas,
),
"to compute vanishing polys"
2021-04-21 22:31:45 +02:00
);
// Compute the quotient polynomials, aka `t` in the Plonk paper.
let all_quotient_poly_chunks = timed!(
2021-06-24 11:45:16 +02:00
quotient_polys
.into_par_iter()
2021-06-24 11:45:16 +02:00
.flat_map(|mut quotient_poly| {
quotient_poly.trim();
quotient_poly.pad(quotient_degree).expect(
2021-06-30 18:54:28 +02:00
"The quotient polynomial doesn't have the right degree. \
This may be because the `Z`s polynomials are still too high degree.",
);
2021-05-07 11:30:03 +02:00
// Split t into degree-n chunks.
2021-06-24 11:45:16 +02:00
quotient_poly.chunks(degree)
})
.collect(),
"to compute quotient polys"
);
let quotient_polys_commitment = timed!(
ListPolynomialCommitment::new_from_polys(
all_quotient_poly_chunks,
fri_config.rate_bits,
2021-06-25 11:49:29 +02:00
PlonkPolynomials::QUOTIENT.blinding
),
"to commit to quotient polys"
2021-04-21 22:31:45 +02:00
);
2021-03-30 11:46:58 -07:00
2021-05-11 10:01:35 +02:00
challenger.observe_hash(&quotient_polys_commitment.merkle_tree.root);
2021-05-06 23:14:37 +02:00
let zeta = challenger.get_extension_challenge();
2021-05-06 23:14:37 +02:00
2021-06-17 11:31:14 +02:00
let (opening_proof, openings) = timed!(
ListPolynomialCommitment::open_plonk(
2021-05-07 16:49:27 +02:00
&[
2021-06-25 11:24:26 +02:00
&prover_data.constants_sigmas_commitment,
2021-05-07 16:49:27 +02:00
&wires_commitment,
2021-07-01 17:28:30 +02:00
&zs_partial_products_commitment,
2021-05-07 16:49:27 +02:00
&quotient_polys_commitment,
],
zeta,
2021-05-07 16:49:27 +02:00
&mut challenger,
2021-06-25 11:24:26 +02:00
common_data,
2021-05-07 16:49:27 +02:00
),
"to compute opening proofs"
2021-05-06 23:14:37 +02:00
);
2021-04-21 22:31:45 +02:00
info!(
"{:.3}s for overall witness & proof generation",
start_proof_gen.elapsed().as_secs_f32()
);
2021-03-21 11:57:33 -07:00
2021-03-30 10:02:00 -07:00
Proof {
2021-05-06 23:14:37 +02:00
wires_root: wires_commitment.merkle_tree.root,
2021-07-01 17:28:30 +02:00
plonk_zs_root: zs_partial_products_commitment.merkle_tree.root,
2021-05-06 23:14:37 +02:00
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
2021-03-21 11:57:33 -07:00
openings,
2021-05-07 16:22:13 +02:00
opening_proof,
2021-03-21 11:57:33 -07:00
}
}
2021-07-01 17:28:30 +02:00
/// Compute the partial products used in the `Z` polynomials.
2021-06-30 15:05:40 +02:00
fn all_wires_permutation_partial_products<F: Extendable<D>, const D: usize>(
witness: &Witness<F>,
betas: &[F],
gammas: &[F],
prover_data: &ProverOnlyCircuitData<F, D>,
common_data: &CommonCircuitData<F, D>,
2021-06-30 15:05:40 +02:00
) -> Vec<Vec<PolynomialValues<F>>> {
2021-05-14 08:07:00 -07:00
(0..common_data.config.num_challenges)
2021-06-30 15:05:40 +02:00
.map(|i| {
wires_permutation_partial_products(
witness,
betas[i],
gammas[i],
prover_data,
common_data,
)
})
.collect()
}
2021-07-01 17:28:30 +02:00
/// Compute the partial products used in the `Z` polynomial.
/// Returns the polynomials interpolating `partial_products(f) + partial_products(g)`
/// where `f, g` are the products in the definition of `Z`: `Z(g^i) = n / d`.
2021-06-30 15:05:40 +02:00
fn wires_permutation_partial_products<F: Extendable<D>, const D: usize>(
witness: &Witness<F>,
beta: F,
gamma: F,
prover_data: &ProverOnlyCircuitData<F, D>,
common_data: &CommonCircuitData<F, D>,
2021-06-30 15:05:40 +02:00
) -> Vec<PolynomialValues<F>> {
2021-06-30 18:54:28 +02:00
let degree = common_data.max_filtered_constraint_degree;
let subgroup = &prover_data.subgroup;
let k_is = &common_data.k_is;
2021-07-01 15:20:16 +02:00
let values = subgroup
2021-07-02 10:58:59 +02:00
.par_iter()
2021-07-01 15:20:16 +02:00
.enumerate()
.map(|(i, &x)| {
let s_sigmas = &prover_data.sigmas[i];
let numerator_values = (0..common_data.config.num_routed_wires)
.map(|j| {
let wire_value = witness.get_wire(i, j);
let k_i = k_is[j];
let s_id = k_i * x;
wire_value + beta * s_id + gamma
})
.collect::<Vec<_>>();
let denominator_values = (0..common_data.config.num_routed_wires)
.map(|j| {
let wire_value = witness.get_wire(i, j);
let s_sigma = s_sigmas[j];
wire_value + beta * s_sigma + gamma
})
.collect::<Vec<_>>();
2021-07-01 17:28:30 +02:00
2021-07-01 15:20:16 +02:00
let numerator_partials = partial_products(&numerator_values, degree);
let denominator_partials = partial_products(&denominator_values, degree);
2021-07-01 17:28:30 +02:00
// This is the final product for the numerator.
2021-07-01 15:41:01 +02:00
let numerator = numerator_partials
[common_data.num_partial_products.0 - common_data.num_partial_products.1..]
2021-07-01 15:20:16 +02:00
.iter()
.copied()
.product();
2021-07-01 17:28:30 +02:00
// This is the final product for the denominator.
2021-07-01 15:41:01 +02:00
let denominator = denominator_partials
[common_data.num_partial_products.0 - common_data.num_partial_products.1..]
2021-07-01 15:20:16 +02:00
.iter()
.copied()
.product();
2021-07-01 17:28:30 +02:00
// We add the numerator and denominator at the beginning of the vector to reuse them
// later in the computation of `Z`.
2021-07-01 15:20:16 +02:00
[
vec![numerator],
vec![denominator],
2021-07-01 15:41:01 +02:00
numerator_partials,
denominator_partials,
2021-07-01 15:20:16 +02:00
]
.concat()
})
.collect::<Vec<_>>();
2021-06-30 15:05:40 +02:00
transpose(&values)
.into_par_iter()
.map(PolynomialValues::new)
.collect()
}
fn compute_zs<F: Extendable<D>, const D: usize>(
partial_products: &[Vec<PolynomialValues<F>>],
common_data: &CommonCircuitData<F, D>,
) -> Vec<PolynomialValues<F>> {
(0..common_data.config.num_challenges)
2021-07-01 17:28:30 +02:00
.map(|i| compute_z(&partial_products[i], common_data))
2021-06-30 15:05:40 +02:00
.collect()
}
2021-07-01 17:28:30 +02:00
/// Compute the `Z` polynomial by reusing the computations done in `wires_permutation_partial_products`.
2021-06-30 15:05:40 +02:00
fn compute_z<F: Extendable<D>, const D: usize>(
partial_products: &[PolynomialValues<F>],
common_data: &CommonCircuitData<F, D>,
) -> PolynomialValues<F> {
let mut plonk_z_points = vec![F::ONE];
for i in 1..common_data.degree() {
2021-07-01 15:20:16 +02:00
let numerator = partial_products[0].values[i - 1];
let denominator = partial_products[1].values[i - 1];
let last = *plonk_z_points.last().unwrap();
plonk_z_points.push(last * numerator / denominator);
}
plonk_z_points.into()
}
2021-06-24 11:45:16 +02:00
fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
common_data: &CommonCircuitData<F, D>,
2021-06-24 11:45:16 +02:00
prover_data: &'a ProverOnlyCircuitData<F, D>,
wires_commitment: &'a ListPolynomialCommitment<F>,
2021-06-30 18:54:28 +02:00
zs_partial_products_commitment: &'a ListPolynomialCommitment<F>,
betas: &[F],
gammas: &[F],
alphas: &[F],
2021-06-24 11:45:16 +02:00
) -> Vec<PolynomialCoeffs<F>> {
2021-05-14 08:07:00 -07:00
let num_challenges = common_data.config.num_challenges;
let max_filtered_constraint_degree_bits = log2_ceil(common_data.max_filtered_constraint_degree);
2021-06-24 11:45:16 +02:00
assert!(
max_filtered_constraint_degree_bits <= common_data.config.rate_bits,
2021-06-24 11:45:16 +02:00
"Having constraints of degree higher than the rate is not supported yet. \
If we need this in the future, we can precompute the larger LDE before computing the `ListPolynomialCommitment`s."
);
// We reuse the LDE computed in `ListPolynomialCommitment` and extract every `step` points to get
// an LDE matching `max_filtered_constraint_degree`.
let step = 1 << (common_data.config.rate_bits - max_filtered_constraint_degree_bits);
2021-06-24 11:45:16 +02:00
// When opening the `Z`s polys at the "next" point in Plonk, need to look at the point `next_step`
// steps away since we work on an LDE of degree `max_filtered_constraint_degree`.
let next_step = 1 << max_filtered_constraint_degree_bits;
2021-06-24 11:45:16 +02:00
let points =
F::two_adic_subgroup(common_data.degree_bits + max_filtered_constraint_degree_bits);
let lde_size = points.len();
2021-06-24 11:45:16 +02:00
// Retrieve the LDE values at index `i`.
let get_at_index = |comm: &'a ListPolynomialCommitment<F>, i: usize| -> &'a [F] {
comm.get_lde_values(i * step)
};
let z_h_on_coset =
ZeroPolyOnCoset::new(common_data.degree_bits, max_filtered_constraint_degree_bits);
2021-06-24 15:42:29 +02:00
2021-06-24 11:45:16 +02:00
let quotient_values: Vec<Vec<F>> = points
2021-07-02 10:58:59 +02:00
.into_par_iter()
2021-04-21 22:31:45 +02:00
.enumerate()
.map(|(i, x)| {
2021-06-24 14:11:47 +02:00
let shifted_x = F::coset_shift() * x;
2021-06-24 11:45:16 +02:00
let i_next = (i + next_step) % lde_size;
2021-06-25 11:24:26 +02:00
let local_constants_sigmas = get_at_index(&prover_data.constants_sigmas_commitment, i);
let local_constants = &local_constants_sigmas[common_data.constants_range()];
let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()];
2021-06-24 15:49:36 +02:00
let local_wires = get_at_index(wires_commitment, i);
2021-06-30 18:54:28 +02:00
let local_zs_partial_products = get_at_index(zs_partial_products_commitment, i);
let local_zs = &local_zs_partial_products[common_data.zs_range()];
let next_zs =
&get_at_index(zs_partial_products_commitment, i_next)[common_data.zs_range()];
2021-07-02 09:55:28 +02:00
let partial_products = &local_zs_partial_products[common_data.partial_products_range()];
2021-04-21 22:31:45 +02:00
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
2021-06-30 18:54:28 +02:00
debug_assert_eq!(local_zs.len(), num_challenges);
2021-04-21 22:31:45 +02:00
let vars = EvaluationVarsBase {
2021-04-21 22:31:45 +02:00
local_constants,
local_wires,
};
2021-06-24 11:45:16 +02:00
let mut quotient_values = eval_vanishing_poly_base(
2021-04-21 22:31:45 +02:00
common_data,
2021-06-24 15:42:29 +02:00
i,
2021-06-24 14:11:47 +02:00
shifted_x,
2021-04-21 22:31:45 +02:00
vars,
2021-06-30 18:54:28 +02:00
local_zs,
next_zs,
2021-07-02 09:55:28 +02:00
partial_products,
2021-04-21 22:31:45 +02:00
s_sigmas,
betas,
gammas,
2021-04-21 22:31:45 +02:00
alphas,
2021-06-24 15:42:29 +02:00
&z_h_on_coset,
2021-06-24 11:45:16 +02:00
);
2021-06-24 15:42:29 +02:00
let denominator_inv = z_h_on_coset.eval_inverse(i);
2021-06-24 11:45:16 +02:00
quotient_values
.iter_mut()
.for_each(|v| *v *= denominator_inv);
quotient_values
2021-04-21 22:31:45 +02:00
})
.collect();
2021-06-24 11:45:16 +02:00
transpose(&quotient_values)
2021-06-24 22:32:52 +02:00
.into_par_iter()
.map(PolynomialValues::new)
2021-06-24 14:11:47 +02:00
.map(|values| values.coset_ifft(F::coset_shift()))
.collect()
}