Update PLONK prover.

This commit is contained in:
wborgeaud 2021-05-06 23:14:37 +02:00
parent 0bae47bedb
commit ea7926bd95
4 changed files with 110 additions and 40 deletions

View File

@ -12,7 +12,7 @@ use anyhow::Result;
pub const SALT_SIZE: usize = 2; pub const SALT_SIZE: usize = 2;
struct ListPolynomialCommitment<F: Field> { pub struct ListPolynomialCommitment<F: Field> {
pub polynomials: Vec<PolynomialCoeffs<F>>, pub polynomials: Vec<PolynomialCoeffs<F>>,
pub fri_config: FriConfig, pub fri_config: FriConfig,
pub merkle_tree: MerkleTree<F>, pub merkle_tree: MerkleTree<F>,

View File

@ -26,6 +26,9 @@ impl<F: Field> PolynomialValues<F> {
self.values.len() self.values.len()
} }
pub fn ifft(self) -> PolynomialCoeffs<F> {
ifft(self)
}
pub fn lde_multiple(polys: Vec<Self>, rate_bits: usize) -> Vec<Self> { pub fn lde_multiple(polys: Vec<Self>, rate_bits: usize) -> Vec<Self> {
polys.into_iter().map(|p| p.lde(rate_bits)).collect() polys.into_iter().map(|p| p.lde(rate_bits)).collect()
} }

View File

@ -1,5 +1,6 @@
use crate::field::field::Field; use crate::field::field::Field;
use crate::merkle_proofs::{MerkleProof, MerkleProofTarget}; use crate::merkle_proofs::{MerkleProof, MerkleProofTarget};
use crate::polynomial::commitment::ListPolynomialCommitment;
use crate::polynomial::polynomial::PolynomialCoeffs; use crate::polynomial::polynomial::PolynomialCoeffs;
use crate::target::Target; use crate::target::Target;
use std::convert::TryInto; use std::convert::TryInto;
@ -136,6 +137,28 @@ pub struct OpeningSet<F: Field> {
pub quotient_polys: Vec<F>, pub quotient_polys: Vec<F>,
} }
impl<F: Field> OpeningSet<F> {
pub fn new(
z: F,
constant_commitment: &ListPolynomialCommitment<F>,
plonk_sigmas_commitment: &ListPolynomialCommitment<F>,
wires_commitment: &ListPolynomialCommitment<F>,
plonk_zs_commitment: &ListPolynomialCommitment<F>,
quotient_polys_commitment: &ListPolynomialCommitment<F>,
) -> Self {
let eval_commitment = |z: F, c: &ListPolynomialCommitment<F>| {
c.polynomials.iter().map(|p| p.eval(z)).collect::<Vec<_>>()
};
Self {
constants: eval_commitment(z, constant_commitment),
plonk_sigmas: eval_commitment(z, plonk_sigmas_commitment),
wires: eval_commitment(z, wires_commitment),
plonk_zs: eval_commitment(z, plonk_zs_commitment),
quotient_polys: eval_commitment(z, quotient_polys_commitment),
}
}
}
/// The purported values of each polynomial at a single point. /// The purported values of each polynomial at a single point.
pub struct OpeningSetTarget { pub struct OpeningSetTarget {
pub constants: Vec<Target>, pub constants: Vec<Target>,

View File

@ -6,13 +6,15 @@ use rayon::prelude::*;
use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
use crate::field::fft::{fft, ifft}; use crate::field::fft::{fft, ifft};
use crate::field::field::Field; use crate::field::field::Field;
use crate::fri::FriConfig;
use crate::generator::generate_partial_witness; use crate::generator::generate_partial_witness;
use crate::merkle_tree::MerkleTree; use crate::merkle_tree::MerkleTree;
use crate::plonk_challenger::Challenger; use crate::plonk_challenger::Challenger;
use crate::plonk_common::{eval_l_1, evaluate_gate_constraints, reduce_with_powers_multi}; use crate::plonk_common::{eval_l_1, evaluate_gate_constraints, reduce_with_powers_multi};
use crate::polynomial::commitment::ListPolynomialCommitment;
use crate::polynomial::division::divide_by_z_h; use crate::polynomial::division::divide_by_z_h;
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
use crate::proof::Proof; use crate::proof::{OpeningSet, Proof};
use crate::util::{transpose, transpose_poly_values}; use crate::util::{transpose, transpose_poly_values};
use crate::vars::EvaluationVars; use crate::vars::EvaluationVars;
use crate::wire::Wire; use crate::wire::Wire;
@ -23,6 +25,14 @@ pub(crate) fn prove<F: Field>(
common_data: &CommonCircuitData<F>, common_data: &CommonCircuitData<F>,
inputs: PartialWitness<F>, inputs: PartialWitness<F>,
) -> Proof<F> { ) -> Proof<F> {
// 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,
};
let start_proof_gen = Instant::now(); let start_proof_gen = Instant::now();
let start_witness = Instant::now(); let start_witness = Instant::now();
@ -41,10 +51,10 @@ pub(crate) fn prove<F: Field>(
let start_wire_ldes = Instant::now(); let start_wire_ldes = Instant::now();
let degree = common_data.degree(); let degree = common_data.degree();
let wire_ldes = (0..num_wires) let wires_polynomials: Vec<PolynomialCoeffs<F>> = (0..num_wires)
.into_par_iter() .into_par_iter()
.map(|i| compute_wire_lde(i, &witness, degree, config.rate_bits)) .map(|i| compute_wire_polynomial(i, &witness, degree))
.collect::<Vec<_>>(); .collect();
info!( info!(
"{:.3}s to compute wire LDEs", "{:.3}s to compute wire LDEs",
start_wire_ldes.elapsed().as_secs_f32() start_wire_ldes.elapsed().as_secs_f32()
@ -52,19 +62,11 @@ pub(crate) fn prove<F: Field>(
// TODO: Could try parallelizing the transpose, or not doing it explicitly, instead having // TODO: Could try parallelizing the transpose, or not doing it explicitly, instead having
// merkle_root_bit_rev_order do it implicitly. // merkle_root_bit_rev_order do it implicitly.
let start_wire_transpose = Instant::now(); let start_wires_commitment = Instant::now();
let wire_ldes_t = transpose_poly_values(wire_ldes); let wires_commitment = ListPolynomialCommitment::new(wires_polynomials, &fri_config);
info!( info!(
"{:.3}s to transpose wire LDEs", "{:.3}s to transpose wire LDEs",
start_wire_transpose.elapsed().as_secs_f32() start_wires_commitment.elapsed().as_secs_f32()
);
// TODO: Could avoid cloning if it's significant?
let start_wires_root = Instant::now();
let wires_tree = MerkleTree::new(wire_ldes_t, true);
info!(
"{:.3}s to Merklize wire LDEs",
start_wires_root.elapsed().as_secs_f32()
); );
let mut challenger = Challenger::new(); let mut challenger = Challenger::new();
@ -72,27 +74,25 @@ pub(crate) fn prove<F: Field>(
// TODO: Need to include public inputs as well. // TODO: Need to include public inputs as well.
challenger.observe_hash(&common_data.circuit_digest); challenger.observe_hash(&common_data.circuit_digest);
challenger.observe_hash(&wires_tree.root); challenger.observe_hash(&wires_commitment.merkle_tree.root);
let betas = challenger.get_n_challenges(num_checks); let betas = challenger.get_n_challenges(num_checks);
let gammas = challenger.get_n_challenges(num_checks); let gammas = challenger.get_n_challenges(num_checks);
let start_plonk_z = Instant::now(); let start_plonk_z = Instant::now();
let plonk_z_vecs = compute_zs(&common_data); let plonk_z_vecs = compute_zs(&common_data);
let plonk_z_ldes = PolynomialValues::lde_multiple(plonk_z_vecs, config.rate_bits);
let plonk_z_ldes_t = transpose_poly_values(plonk_z_ldes);
info!( info!(
"{:.3}s to compute Z's and their LDEs", "{:.3}s to compute Z's",
start_plonk_z.elapsed().as_secs_f32() start_plonk_z.elapsed().as_secs_f32()
); );
let start_plonk_z_root = Instant::now(); let start_plonk_z_root = Instant::now();
let plonk_zs_tree = MerkleTree::new(plonk_z_ldes_t, true); let plonk_zs_commitment = ListPolynomialCommitment::new(plonk_z_vecs, &fri_config);
info!( info!(
"{:.3}s to Merklize Z's", "{:.3}s to Merklize Z's",
start_plonk_z_root.elapsed().as_secs_f32() start_plonk_z_root.elapsed().as_secs_f32()
); );
challenger.observe_hash(&plonk_zs_tree.root); challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
let alphas = challenger.get_n_challenges(num_checks); let alphas = challenger.get_n_challenges(num_checks);
@ -100,8 +100,8 @@ pub(crate) fn prove<F: Field>(
let vanishing_polys = compute_vanishing_polys( let vanishing_polys = compute_vanishing_polys(
common_data, common_data,
prover_data, prover_data,
&wires_tree, &wires_commitment.merkle_tree,
&plonk_zs_tree, &plonk_zs_commitment.merkle_tree,
&betas, &betas,
&gammas, &gammas,
&alphas, &alphas,
@ -113,28 +113,53 @@ pub(crate) fn prove<F: Field>(
// Compute the quotient polynomials, aka `t` in the Plonk paper. // Compute the quotient polynomials, aka `t` in the Plonk paper.
let quotient_polys_start = Instant::now(); let quotient_polys_start = Instant::now();
let mut all_quotient_poly_chunk_ldes = Vec::with_capacity(num_checks * quotient_degree); let mut all_quotient_poly_chunks = Vec::with_capacity(num_checks * quotient_degree);
for vanishing_poly in vanishing_polys.into_iter() { for vanishing_poly in vanishing_polys.into_iter() {
let vanishing_poly_coeff = ifft(vanishing_poly); let vanishing_poly_coeff = ifft(vanishing_poly);
let quotient_poly_coeff = divide_by_z_h(vanishing_poly_coeff, degree); let quotient_poly_coeff = divide_by_z_h(vanishing_poly_coeff, degree);
// Split t into degree-n chunks. // Split t into degree-n chunks.
let quotient_poly_coeff_chunks = quotient_poly_coeff.chunks(degree); let quotient_poly_coeff_chunks = quotient_poly_coeff.chunks(degree);
let quotient_poly_coeff_ldes = all_quotient_poly_chunks.extend(quotient_poly_coeff_chunks);
PolynomialCoeffs::lde_multiple(quotient_poly_coeff_chunks, config.rate_bits);
let quotient_poly_chunk_ldes: Vec<PolynomialValues<F>> =
quotient_poly_coeff_ldes.into_par_iter().map(fft).collect();
all_quotient_poly_chunk_ldes.extend(quotient_poly_chunk_ldes);
} }
let quotient_polys_tree = let quotient_polys_commitment =
MerkleTree::new(transpose_poly_values(all_quotient_poly_chunk_ldes), true); ListPolynomialCommitment::new(all_quotient_poly_chunks, &fri_config);
info!( info!(
"{:.3}s to compute quotient polys and their LDEs", "{:.3}s to compute quotient polys and their LDEs",
quotient_polys_start.elapsed().as_secs_f32() quotient_polys_start.elapsed().as_secs_f32()
); );
let openings = Vec::new(); // TODO challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
let fri_proofs = Vec::new(); // TODO // 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<_>>();
// 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,
);
info!( info!(
"{:.3}s for overall witness & proof generation", "{:.3}s for overall witness & proof generation",
@ -142,22 +167,22 @@ pub(crate) fn prove<F: Field>(
); );
Proof { Proof {
wires_root: wires_tree.root, wires_root: wires_commitment.merkle_tree.root,
plonk_zs_root: plonk_zs_tree.root, plonk_zs_root: plonk_zs_commitment.merkle_tree.root,
quotient_polys_root: quotient_polys_tree.root, quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
openings, openings,
fri_proofs, fri_proofs,
} }
} }
fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<PolynomialValues<F>> { fn compute_zs<F: Field>(common_data: &CommonCircuitData<F>) -> Vec<PolynomialCoeffs<F>> {
(0..common_data.config.num_checks) (0..common_data.config.num_checks)
.map(|i| compute_z(common_data, i)) .map(|i| compute_z(common_data, i))
.collect() .collect()
} }
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> PolynomialValues<F> { fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> PolynomialCoeffs<F> {
PolynomialValues::zero(common_data.degree()) // TODO PolynomialCoeffs::zero(common_data.degree()) // TODO
} }
// TODO: Parallelize. // TODO: Parallelize.
@ -263,6 +288,25 @@ fn compute_vanishing_poly_entry<F: Field>(
reduce_with_powers_multi(&vanishing_terms, alphas) reduce_with_powers_multi(&vanishing_terms, alphas)
} }
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()
}
fn compute_wire_lde<F: Field>( fn compute_wire_lde<F: Field>(
input: usize, input: usize,
witness: &PartialWitness<F>, witness: &PartialWitness<F>,