plonky2/src/prover.rs

329 lines
11 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};
use crate::field::fft::{fft, ifft};
2021-02-09 21:25:21 -08:00
use crate::field::field::Field;
2021-05-06 23:14:37 +02:00
use crate::fri::FriConfig;
2021-03-21 11:17:00 -07:00
use crate::generator::generate_partial_witness;
2021-04-24 11:20:07 -07:00
use crate::merkle_tree::MerkleTree;
use crate::plonk_challenger::Challenger;
2021-04-21 22:31:45 +02:00
use crate::plonk_common::{eval_l_1, evaluate_gate_constraints, reduce_with_powers_multi};
2021-05-06 23:14:37 +02:00
use crate::polynomial::commitment::ListPolynomialCommitment;
2021-03-30 20:16:20 -07:00
use crate::polynomial::division::divide_by_z_h;
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
2021-05-06 23:14:37 +02:00
use crate::proof::{OpeningSet, Proof};
2021-04-01 16:31:55 -07:00
use crate::util::{transpose, transpose_poly_values};
2021-04-21 22:31:45 +02:00
use crate::vars::EvaluationVars;
2021-03-21 11:57:33 -07:00
use crate::wire::Wire;
2021-03-21 11:17:00 -07:00
use crate::witness::PartialWitness;
2021-02-09 21:25:21 -08:00
2021-03-21 11:17:00 -07:00
pub(crate) fn prove<F: Field>(
2021-02-09 21:25:21 -08:00
prover_data: &ProverOnlyCircuitData<F>,
common_data: &CommonCircuitData<F>,
2021-03-21 11:17:00 -07:00
inputs: PartialWitness<F>,
2021-03-30 10:02:00 -07:00
) -> Proof<F> {
2021-05-06 23:14:37 +02:00
// TODO: Change this to real values.
let fri_config = FriConfig {
proof_of_work_bits: 1,
rate_bits: 1,
reduction_arity_bits: vec![1],
num_query_rounds: 1,
blinding: true,
};
2021-03-30 23:47:29 -07:00
let start_proof_gen = Instant::now();
2021-03-25 15:20:14 -07:00
let start_witness = Instant::now();
2021-03-30 23:47:29 -07:00
let mut witness = inputs;
2021-03-25 15:20:14 -07:00
info!("Running {} generators", prover_data.generators.len());
2021-03-21 11:17:00 -07:00
generate_partial_witness(&mut witness, &prover_data.generators);
2021-04-21 22:31:45 +02:00
info!(
"{:.3}s to generate witness",
start_witness.elapsed().as_secs_f32()
);
2021-03-21 11:17:00 -07:00
2021-03-21 11:57:33 -07:00
let config = common_data.config;
let num_wires = config.num_wires;
let num_checks = config.num_checks;
let quotient_degree = common_data.quotient_degree();
2021-03-25 15:20:14 -07:00
let start_wire_ldes = Instant::now();
2021-03-30 10:02:00 -07:00
let degree = common_data.degree();
2021-05-06 23:14:37 +02:00
let wires_polynomials: Vec<PolynomialCoeffs<F>> = (0..num_wires)
2021-03-30 10:02:00 -07:00
.into_par_iter()
2021-05-06 23:14:37 +02:00
.map(|i| compute_wire_polynomial(i, &witness, degree))
.collect();
2021-04-21 22:31:45 +02:00
info!(
"{:.3}s to compute wire LDEs",
start_wire_ldes.elapsed().as_secs_f32()
);
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-06 23:14:37 +02:00
let start_wires_commitment = Instant::now();
let wires_commitment = ListPolynomialCommitment::new(wires_polynomials, &fri_config);
2021-04-21 22:31:45 +02:00
info!(
"{:.3}s to transpose wire LDEs",
2021-05-06 23:14:37 +02:00
start_wires_commitment.elapsed().as_secs_f32()
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);
let betas = challenger.get_n_challenges(num_checks);
let gammas = challenger.get_n_challenges(num_checks);
2021-03-31 21:15:24 -07:00
2021-03-30 23:47:29 -07:00
let start_plonk_z = Instant::now();
let plonk_z_vecs = compute_zs(&common_data);
2021-04-21 22:31:45 +02:00
info!(
2021-05-06 23:14:37 +02:00
"{:.3}s to compute Z's",
2021-04-21 22:31:45 +02:00
start_plonk_z.elapsed().as_secs_f32()
);
2021-03-30 23:47:29 -07:00
let start_plonk_z_root = Instant::now();
2021-05-06 23:14:37 +02:00
let plonk_zs_commitment = ListPolynomialCommitment::new(plonk_z_vecs, &fri_config);
2021-04-21 22:31:45 +02:00
info!(
"{:.3}s to Merklize Z's",
start_plonk_z_root.elapsed().as_secs_f32()
);
2021-05-06 23:14:37 +02:00
challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
2021-03-31 21:15:24 -07:00
let alphas = challenger.get_n_challenges(num_checks);
2021-03-31 21:15:24 -07:00
let start_vanishing_polys = Instant::now();
let vanishing_polys = compute_vanishing_polys(
2021-04-21 22:31:45 +02:00
common_data,
prover_data,
2021-05-06 23:14:37 +02:00
&wires_commitment.merkle_tree,
&plonk_zs_commitment.merkle_tree,
&betas,
&gammas,
2021-04-21 22:31:45 +02:00
&alphas,
);
info!(
"{:.3}s to compute vanishing polys",
start_vanishing_polys.elapsed().as_secs_f32()
);
// Compute the quotient polynomials, aka `t` in the Plonk paper.
let quotient_polys_start = Instant::now();
2021-05-06 23:14:37 +02:00
let mut all_quotient_poly_chunks = Vec::with_capacity(num_checks * quotient_degree);
for vanishing_poly in vanishing_polys.into_iter() {
let vanishing_poly_coeff = ifft(vanishing_poly);
let quotient_poly_coeff = divide_by_z_h(vanishing_poly_coeff, degree);
// Split t into degree-n chunks.
let quotient_poly_coeff_chunks = quotient_poly_coeff.chunks(degree);
2021-05-06 23:14:37 +02:00
all_quotient_poly_chunks.extend(quotient_poly_coeff_chunks);
}
2021-05-06 23:14:37 +02:00
let quotient_polys_commitment =
ListPolynomialCommitment::new(all_quotient_poly_chunks, &fri_config);
2021-04-21 22:31:45 +02:00
info!(
"{:.3}s to compute quotient polys and their LDEs",
quotient_polys_start.elapsed().as_secs_f32()
);
2021-03-30 11:46:58 -07:00
2021-05-06 23:14:37 +02:00
challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
// TODO: How many do we need?
let num_zetas = 2;
let zetas = challenger.get_n_challenges(num_zetas);
let openings = zetas
.iter()
.map(|&z| {
OpeningSet::new(
z,
todo!(),
todo!(),
&wires_commitment,
&plonk_zs_commitment,
&quotient_polys_commitment,
)
})
.collect::<Vec<_>>();
2021-03-30 13:30:31 -07:00
2021-05-06 23:14:37 +02:00
// TODO: This re-evaluates the polynomial and is thus redundant with the openings above.
let fri_proofs = ListPolynomialCommitment::batch_open(
&[
&todo!(),
&todo!(),
&wires_commitment,
&plonk_zs_commitment,
&quotient_polys_commitment,
],
&zetas,
&mut challenger,
);
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,
plonk_zs_root: plonk_zs_commitment.merkle_tree.root,
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
2021-03-21 11:57:33 -07:00
openings,
fri_proofs,
2021-03-21 11:57:33 -07:00
}
}
2021-05-06 23:14:37 +02:00
fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<PolynomialCoeffs<F>> {
(0..common_data.config.num_checks)
.map(|i| compute_z(common_data, i))
.collect()
}
2021-05-06 23:14:37 +02:00
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> PolynomialCoeffs<F> {
PolynomialCoeffs::zero(common_data.degree()) // TODO
}
2021-03-30 23:47:29 -07:00
// TODO: Parallelize.
fn compute_vanishing_polys<F: Field>(
common_data: &CommonCircuitData<F>,
prover_data: &ProverOnlyCircuitData<F>,
2021-04-24 11:20:07 -07:00
wires_tree: &MerkleTree<F>,
plonk_zs_tree: &MerkleTree<F>,
betas: &[F],
gammas: &[F],
alphas: &[F],
) -> Vec<PolynomialValues<F>> {
let lde_size = common_data.lde_size();
let lde_gen = common_data.lde_generator();
let num_checks = common_data.config.num_checks;
2021-04-01 13:46:24 -07:00
let points = F::cyclic_subgroup_known_order(lde_gen, lde_size);
2021-04-21 22:31:45 +02:00
let values: Vec<Vec<F>> = points
.into_par_iter()
.enumerate()
.map(|(i, x)| {
let i_next = (i + 1) % lde_size;
2021-04-24 11:20:07 -07:00
let local_wires = &wires_tree.leaves[i];
let local_constants = &prover_data.constants_tree.leaves[i];
2021-04-24 11:20:07 -07:00
let local_plonk_zs = &plonk_zs_tree.leaves[i];
let next_plonk_zs = &plonk_zs_tree.leaves[i_next];
let s_sigmas = &prover_data.sigmas_tree.leaves[i];
2021-04-21 22:31:45 +02:00
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
debug_assert_eq!(local_plonk_zs.len(), num_checks);
let vars = EvaluationVars {
local_constants,
local_wires,
};
compute_vanishing_poly_entry(
common_data,
x,
vars,
local_plonk_zs,
next_plonk_zs,
s_sigmas,
betas,
gammas,
2021-04-21 22:31:45 +02:00
alphas,
)
})
.collect();
2021-04-01 13:46:24 -07:00
transpose(&values)
.into_iter()
.map(PolynomialValues::new)
.collect()
}
2021-03-30 23:12:47 -07:00
/// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random
/// linear combination of gate constraints, plus some other terms relating to the permutation
/// argument. All such terms should vanish on `H`.
fn compute_vanishing_poly_entry<F: Field>(
common_data: &CommonCircuitData<F>,
2021-03-30 23:12:47 -07:00
x: F,
vars: EvaluationVars<F>,
local_plonk_zs: &[F],
next_plonk_zs: &[F],
2021-03-30 23:12:47 -07:00
s_sigmas: &[F],
betas: &[F],
gammas: &[F],
alphas: &[F],
) -> Vec<F> {
2021-04-21 22:31:45 +02:00
let constraint_terms =
evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars);
2021-03-30 23:12:47 -07:00
// The L_1(x) (Z(x) - 1) vanishing terms.
let mut vanishing_z_1_terms = Vec::new();
// The Z(x) f'(x) - g'(x) Z(g x) terms.
let mut vanishing_v_shift_terms = Vec::new();
for i in 0..common_data.config.num_checks {
let z_x = local_plonk_zs[i];
let z_gz = next_plonk_zs[i];
vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::ONE));
let mut f_prime = F::ONE;
let mut g_prime = F::ONE;
for j in 0..common_data.config.num_routed_wires {
let wire_value = vars.local_wires[j];
let k_i = common_data.k_is[j];
let s_id = k_i * x;
let s_sigma = s_sigmas[j];
f_prime *= wire_value + betas[i] * s_id + gammas[i];
g_prime *= wire_value + betas[i] * s_sigma + gammas[i];
2021-03-30 23:12:47 -07:00
}
vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz);
}
let vanishing_terms = [
vanishing_z_1_terms,
vanishing_v_shift_terms,
constraint_terms,
2021-04-21 22:31:45 +02:00
]
.concat();
2021-03-30 23:12:47 -07:00
reduce_with_powers_multi(&vanishing_terms, alphas)
}
2021-05-06 23:14:37 +02:00
fn compute_wire_polynomial<F: Field>(
input: usize,
witness: &PartialWitness<F>,
degree: usize,
) -> PolynomialCoeffs<F> {
let wire_values = (0..degree)
// Some gates do not use all wires, and we do not require that generators populate unused
// wires, so some wire values will not be set. We can set these to any value; here we
// arbitrary pick zero. Ideally we would verify that no constraints operate on these unset
// wires, but that isn't trivial.
.map(|gate| {
witness
.try_get_wire(Wire { gate, input })
.unwrap_or(F::ZERO)
})
.collect();
PolynomialValues::new(wire_values).ifft()
}
2021-03-21 11:57:33 -07:00
fn compute_wire_lde<F: Field>(
input: usize,
witness: &PartialWitness<F>,
degree: usize,
2021-03-25 15:20:14 -07:00
rate_bits: usize,
2021-03-30 13:30:31 -07:00
) -> PolynomialValues<F> {
2021-03-25 15:20:14 -07:00
let wire_values = (0..degree)
2021-03-21 19:50:05 -07:00
// Some gates do not use all wires, and we do not require that generators populate unused
// wires, so some wire values will not be set. We can set these to any value; here we
// arbitrary pick zero. Ideally we would verify that no constraints operate on these unset
// wires, but that isn't trivial.
2021-04-21 22:31:45 +02:00
.map(|gate| {
witness
.try_get_wire(Wire { gate, input })
.unwrap_or(F::ZERO)
})
2021-03-21 11:57:33 -07:00
.collect();
2021-03-30 13:30:31 -07:00
PolynomialValues::new(wire_values).lde(rate_bits)
2021-02-09 21:25:21 -08:00
}