2021-03-25 15:20:14 -07:00
|
|
|
use std::time::Instant;
|
|
|
|
|
|
|
|
|
|
use log::info;
|
2021-03-28 15:36:51 -07:00
|
|
|
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-03-28 15:36:51 -07:00
|
|
|
use crate::constraint_polynomial::EvaluationVars;
|
2021-03-30 13:30:31 -07:00
|
|
|
use crate::field::fft::{fft, ifft};
|
2021-02-09 21:25:21 -08:00
|
|
|
use crate::field::field::Field;
|
2021-03-21 11:17:00 -07:00
|
|
|
use crate::generator::generate_partial_witness;
|
2021-03-30 20:16:20 -07:00
|
|
|
use crate::hash::merkle_root_bit_rev_order;
|
2021-03-30 23:12:47 -07:00
|
|
|
use crate::plonk_common::{reduce_with_powers, eval_l_1};
|
2021-03-30 20:16:20 -07:00
|
|
|
use crate::polynomial::division::divide_by_z_h;
|
|
|
|
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
|
|
|
|
use crate::proof::Proof;
|
|
|
|
|
use crate::util::transpose_poly_values;
|
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-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-03-30 23:47:29 -07:00
|
|
|
info!("{} 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;
|
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-03-21 11:57:33 -07:00
|
|
|
let wire_ldes = (0..num_wires)
|
2021-03-30 10:02:00 -07:00
|
|
|
.into_par_iter()
|
|
|
|
|
.map(|i| compute_wire_lde(i, &witness, degree, config.rate_bits))
|
2021-03-21 11:57:33 -07:00
|
|
|
.collect::<Vec<_>>();
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{} 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.
|
|
|
|
|
let start_wire_transpose = Instant::now();
|
2021-03-30 13:30:31 -07:00
|
|
|
let wire_ldes_t = transpose_poly_values(wire_ldes);
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{} to transpose wire LDEs",
|
|
|
|
|
start_wire_transpose.elapsed().as_secs_f32());
|
2021-03-30 10:02:00 -07:00
|
|
|
|
2021-03-28 15:36:51 -07:00
|
|
|
// TODO: Could avoid cloning if it's significant?
|
2021-03-30 10:02:00 -07:00
|
|
|
let start_wires_root = Instant::now();
|
2021-03-28 15:36:51 -07:00
|
|
|
let wires_root = merkle_root_bit_rev_order(wire_ldes_t.clone());
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{} to Merklizing wire LDEs",
|
|
|
|
|
start_wires_root.elapsed().as_secs_f32());
|
2021-03-21 11:57:33 -07:00
|
|
|
|
2021-03-30 23:47:29 -07:00
|
|
|
let start_plonk_z = Instant::now();
|
2021-03-28 15:36:51 -07:00
|
|
|
let plonk_z_vecs = compute_zs(&common_data);
|
2021-03-30 13:30:31 -07:00
|
|
|
let plonk_z_ldes = PolynomialValues::lde_multiple(plonk_z_vecs, config.rate_bits);
|
|
|
|
|
let plonk_z_ldes_t = transpose_poly_values(plonk_z_ldes);
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{}s to compute Z's and their LDEs",
|
|
|
|
|
start_plonk_z.elapsed().as_secs_f32());
|
|
|
|
|
|
|
|
|
|
let start_plonk_z_root = Instant::now();
|
2021-03-28 15:36:51 -07:00
|
|
|
let plonk_z_root = merkle_root_bit_rev_order(plonk_z_ldes_t.clone());
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{}s to Merklize Z's",
|
|
|
|
|
start_plonk_z_root.elapsed().as_secs_f32());
|
2021-03-28 15:36:51 -07:00
|
|
|
|
2021-03-30 23:12:47 -07:00
|
|
|
let beta = F::ZERO; // TODO
|
|
|
|
|
let gamma = F::ZERO; // TODO
|
2021-03-28 15:36:51 -07:00
|
|
|
let alpha = F::ZERO; // TODO
|
2021-03-21 11:57:33 -07:00
|
|
|
|
2021-03-28 15:36:51 -07:00
|
|
|
let start_vanishing_poly = Instant::now();
|
|
|
|
|
let vanishing_poly = compute_vanishing_poly(
|
2021-03-30 23:12:47 -07:00
|
|
|
common_data, prover_data, wire_ldes_t, plonk_z_ldes_t, beta, gamma, alpha);
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{} to compute vanishing poly",
|
|
|
|
|
start_vanishing_poly.elapsed().as_secs_f32());
|
2021-03-28 15:36:51 -07:00
|
|
|
|
2021-03-30 13:30:31 -07:00
|
|
|
let quotient_poly_start = Instant::now();
|
|
|
|
|
let vanishing_poly_coeffs = ifft(vanishing_poly);
|
|
|
|
|
let plonk_t = divide_by_z_h(vanishing_poly_coeffs, degree);
|
|
|
|
|
// Split t into degree-n chunks.
|
|
|
|
|
let plonk_t_chunks = plonk_t.chunks(degree);
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{} to compute quotient poly",
|
|
|
|
|
quotient_poly_start.elapsed().as_secs_f32());
|
2021-03-30 11:46:58 -07:00
|
|
|
|
2021-03-28 15:36:51 -07:00
|
|
|
// Need to convert to coeff form and back?
|
2021-03-30 13:30:31 -07:00
|
|
|
let plonk_t_ldes = PolynomialCoeffs::lde_multiple(plonk_t_chunks, config.rate_bits);
|
|
|
|
|
let plonk_t_ldes = plonk_t_ldes.into_iter().map(fft).collect();
|
|
|
|
|
let plonk_t_root = merkle_root_bit_rev_order(transpose_poly_values(plonk_t_ldes));
|
2021-03-21 11:57:33 -07:00
|
|
|
|
2021-03-30 13:30:31 -07:00
|
|
|
let openings = Vec::new(); // TODO
|
|
|
|
|
|
2021-03-30 23:47:29 -07:00
|
|
|
info!("{}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-03-21 11:57:33 -07:00
|
|
|
wires_root,
|
|
|
|
|
plonk_z_root,
|
|
|
|
|
plonk_t_root,
|
|
|
|
|
openings,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-30 13:30:31 -07:00
|
|
|
fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<PolynomialValues<F>> {
|
2021-03-28 15:36:51 -07:00
|
|
|
(0..common_data.config.num_checks)
|
|
|
|
|
.map(|i| compute_z(common_data, i))
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-30 13:30:31 -07:00
|
|
|
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> PolynomialValues<F> {
|
|
|
|
|
PolynomialValues::zero(common_data.degree()) // TODO
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
2021-03-30 23:47:29 -07:00
|
|
|
// TODO: Parallelize.
|
2021-03-28 15:36:51 -07:00
|
|
|
fn compute_vanishing_poly<F: Field>(
|
|
|
|
|
common_data: &CommonCircuitData<F>,
|
|
|
|
|
prover_data: &ProverOnlyCircuitData<F>,
|
|
|
|
|
wire_ldes_t: Vec<Vec<F>>,
|
|
|
|
|
plonk_z_lde_t: Vec<Vec<F>>,
|
2021-03-30 23:12:47 -07:00
|
|
|
beta: F,
|
|
|
|
|
gamma: F,
|
2021-03-28 15:36:51 -07:00
|
|
|
alpha: F,
|
2021-03-30 13:30:31 -07:00
|
|
|
) -> PolynomialValues<F> {
|
2021-03-28 15:36:51 -07:00
|
|
|
let lde_size = common_data.lde_size();
|
|
|
|
|
let lde_gen = common_data.lde_generator();
|
|
|
|
|
|
|
|
|
|
let mut result = Vec::with_capacity(lde_size);
|
|
|
|
|
let mut point = F::ONE;
|
|
|
|
|
for i in 0..lde_size {
|
|
|
|
|
debug_assert!(point != F::ONE);
|
|
|
|
|
|
|
|
|
|
let i_next = (i + 1) % lde_size;
|
|
|
|
|
let local_wires = &wire_ldes_t[i];
|
|
|
|
|
let next_wires = &wire_ldes_t[i_next];
|
|
|
|
|
let local_constants = &prover_data.constant_ldes_t[i];
|
|
|
|
|
let next_constants = &prover_data.constant_ldes_t[i_next];
|
|
|
|
|
let local_plonk_zs = &plonk_z_lde_t[i];
|
|
|
|
|
let next_plonk_zs = &plonk_z_lde_t[i_next];
|
2021-03-30 23:12:47 -07:00
|
|
|
let s_sigmas = &prover_data.sigma_ldes_t[i];
|
2021-03-28 15:36:51 -07:00
|
|
|
|
|
|
|
|
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
|
|
|
|
|
debug_assert_eq!(local_plonk_zs.len(), common_data.config.num_checks);
|
|
|
|
|
|
|
|
|
|
let vars = EvaluationVars {
|
|
|
|
|
local_constants,
|
|
|
|
|
next_constants,
|
|
|
|
|
local_wires,
|
|
|
|
|
next_wires,
|
|
|
|
|
};
|
|
|
|
|
result.push(compute_vanishing_poly_entry(
|
2021-03-30 23:12:47 -07:00
|
|
|
common_data, point, vars, local_plonk_zs, next_plonk_zs, s_sigmas, beta, gamma, alpha));
|
2021-03-28 15:36:51 -07:00
|
|
|
|
|
|
|
|
point *= lde_gen;
|
|
|
|
|
}
|
|
|
|
|
debug_assert_eq!(point, F::ONE);
|
2021-03-30 13:30:31 -07:00
|
|
|
PolynomialValues::new(result)
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
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`.
|
2021-03-28 15:36:51 -07:00
|
|
|
fn compute_vanishing_poly_entry<F: Field>(
|
|
|
|
|
common_data: &CommonCircuitData<F>,
|
2021-03-30 23:12:47 -07:00
|
|
|
x: F,
|
2021-03-28 15:36:51 -07:00
|
|
|
vars: EvaluationVars<F>,
|
|
|
|
|
local_plonk_zs: &[F],
|
|
|
|
|
next_plonk_zs: &[F],
|
2021-03-30 23:12:47 -07:00
|
|
|
s_sigmas: &[F],
|
|
|
|
|
beta: F,
|
|
|
|
|
gamma: F,
|
2021-03-28 15:36:51 -07:00
|
|
|
alpha: F,
|
|
|
|
|
) -> F {
|
2021-03-30 23:12:47 -07:00
|
|
|
let constraint_terms = common_data.evaluate(vars);
|
|
|
|
|
|
|
|
|
|
// 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 + beta * s_id + gamma;
|
|
|
|
|
g_prime *= wire_value + beta * s_sigma + gamma;
|
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
|
].concat();
|
|
|
|
|
|
|
|
|
|
reduce_with_powers(vanishing_terms, alpha)
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
.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
|
|
|
}
|