mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-05 07:13:08 +00:00
Batch open for PLONK
This commit is contained in:
parent
ea7926bd95
commit
1bae3a02f6
@ -4,6 +4,7 @@ use plonky2::circuit_builder::CircuitBuilder;
|
||||
use plonky2::circuit_data::CircuitConfig;
|
||||
use plonky2::field::crandall_field::CrandallField;
|
||||
use plonky2::field::field::Field;
|
||||
use plonky2::fri::FriConfig;
|
||||
use plonky2::gates::constant::ConstantGate;
|
||||
use plonky2::gates::gmimc::GMiMCGate;
|
||||
use plonky2::hash::GMIMC_ROUNDS;
|
||||
@ -34,6 +35,13 @@ fn bench_prove<F: Field>() {
|
||||
security_bits: 128,
|
||||
rate_bits: 3,
|
||||
num_checks: 3,
|
||||
fri_config: FriConfig {
|
||||
proof_of_work_bits: 1,
|
||||
rate_bits: 1,
|
||||
reduction_arity_bits: vec![1],
|
||||
num_query_rounds: 1,
|
||||
blinding: true,
|
||||
},
|
||||
};
|
||||
|
||||
let mut builder = CircuitBuilder::<F>::new(config);
|
||||
|
||||
@ -16,6 +16,7 @@ use crate::generator::{CopyGenerator, WitnessGenerator};
|
||||
use crate::hash::hash_n_to_hash;
|
||||
use crate::merkle_tree::MerkleTree;
|
||||
use crate::permutation_argument::TargetPartitions;
|
||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||
use crate::polynomial::polynomial::PolynomialValues;
|
||||
use crate::target::Target;
|
||||
use crate::util::{log2_strict, transpose, transpose_poly_values};
|
||||
@ -138,11 +139,11 @@ impl<F: Field> CircuitBuilder<F> {
|
||||
/// Both elements must be routable, otherwise this method will panic.
|
||||
pub fn assert_equal(&mut self, x: Target, y: Target) {
|
||||
assert!(
|
||||
x.is_routable(self.config),
|
||||
x.is_routable(&self.config),
|
||||
"Tried to route a wire that isn't routable"
|
||||
);
|
||||
assert!(
|
||||
y.is_routable(self.config),
|
||||
y.is_routable(&self.config),
|
||||
"Tried to route a wire that isn't routable"
|
||||
);
|
||||
self.copy_constraints.push((x, y));
|
||||
@ -271,18 +272,20 @@ impl<F: Field> CircuitBuilder<F> {
|
||||
info!("degree after blinding & padding: {}", degree);
|
||||
|
||||
let constant_vecs = self.constant_polys();
|
||||
let constant_ldes = PolynomialValues::lde_multiple(constant_vecs, self.config.rate_bits);
|
||||
let constant_ldes_t = transpose_poly_values(constant_ldes);
|
||||
let constants_tree = MerkleTree::new(constant_ldes_t, true);
|
||||
let constants_commitment = ListPolynomialCommitment::new(
|
||||
constant_vecs.into_iter().map(|v| v.ifft()).collect(),
|
||||
&self.config.fri_config,
|
||||
);
|
||||
|
||||
let k_is = get_unique_coset_shifts(degree, self.config.num_routed_wires);
|
||||
let sigma_vecs = self.sigma_vecs(&k_is);
|
||||
let sigma_ldes = PolynomialValues::lde_multiple(sigma_vecs, self.config.rate_bits);
|
||||
let sigma_ldes_t = transpose_poly_values(sigma_ldes);
|
||||
let sigmas_tree = MerkleTree::new(sigma_ldes_t, true);
|
||||
let sigmas_commitment = ListPolynomialCommitment::new(
|
||||
sigma_vecs.into_iter().map(|v| v.ifft()).collect(),
|
||||
&self.config.fri_config,
|
||||
);
|
||||
|
||||
let constants_root = constants_tree.root;
|
||||
let sigmas_root = sigmas_tree.root;
|
||||
let constants_root = constants_commitment.merkle_tree.root;
|
||||
let sigmas_root = sigmas_commitment.merkle_tree.root;
|
||||
let verifier_only = VerifierOnlyCircuitData {
|
||||
constants_root,
|
||||
sigmas_root,
|
||||
@ -291,8 +294,8 @@ impl<F: Field> CircuitBuilder<F> {
|
||||
let generators = self.generators;
|
||||
let prover_only = ProverOnlyCircuitData {
|
||||
generators,
|
||||
constants_tree,
|
||||
sigmas_tree,
|
||||
constants_commitment,
|
||||
sigmas_commitment,
|
||||
};
|
||||
|
||||
// The HashSet of gates will have a non-deterministic order. When converting to a Vec, we
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
use crate::field::field::Field;
|
||||
use crate::fri::FriConfig;
|
||||
use crate::gates::gate::GateRef;
|
||||
use crate::generator::WitnessGenerator;
|
||||
use crate::merkle_tree::MerkleTree;
|
||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||
use crate::proof::{Hash, HashTarget, Proof};
|
||||
use crate::prover::prove;
|
||||
use crate::verifier::verify;
|
||||
use crate::witness::PartialWitness;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct CircuitConfig {
|
||||
pub num_wires: usize,
|
||||
pub num_routed_wires: usize,
|
||||
@ -15,6 +17,9 @@ pub struct CircuitConfig {
|
||||
pub rate_bits: usize,
|
||||
/// The number of times to repeat checks that have soundness errors of (roughly) `degree / |F|`.
|
||||
pub num_checks: usize,
|
||||
|
||||
// TODO: Find a better place for this.
|
||||
pub fri_config: FriConfig,
|
||||
}
|
||||
|
||||
impl Default for CircuitConfig {
|
||||
@ -25,6 +30,13 @@ impl Default for CircuitConfig {
|
||||
security_bits: 128,
|
||||
rate_bits: 3,
|
||||
num_checks: 3,
|
||||
fri_config: FriConfig {
|
||||
proof_of_work_bits: 1,
|
||||
rate_bits: 1,
|
||||
reduction_arity_bits: vec![1],
|
||||
num_query_rounds: 1,
|
||||
blinding: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,10 +97,10 @@ impl<F: Field> VerifierCircuitData<F> {
|
||||
/// Circuit data required by the prover, but not the verifier.
|
||||
pub(crate) struct ProverOnlyCircuitData<F: Field> {
|
||||
pub generators: Vec<Box<dyn WitnessGenerator<F>>>,
|
||||
/// Merkle tree containing LDEs of each constant polynomial.
|
||||
pub constants_tree: MerkleTree<F>,
|
||||
/// Merkle tree containing LDEs of each sigma polynomial.
|
||||
pub sigmas_tree: MerkleTree<F>,
|
||||
/// Commitments to the constants polynomial.
|
||||
pub constants_commitment: ListPolynomialCommitment<F>,
|
||||
/// Commitments to the sigma polynomial.
|
||||
pub sigmas_commitment: ListPolynomialCommitment<F>,
|
||||
}
|
||||
|
||||
/// Circuit data required by the verifier, but not the prover.
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::plonk_challenger::Challenger;
|
||||
use crate::plonk_common::reduce_with_powers;
|
||||
use crate::polynomial::old_polynomial::Polynomial;
|
||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||
use crate::proof::{FriProof, Hash};
|
||||
use crate::proof::{FriProof, Hash, OpeningSet};
|
||||
use crate::util::{log2_strict, reverse_index_bits_in_place, transpose};
|
||||
use anyhow::Result;
|
||||
|
||||
@ -122,7 +122,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
||||
commitments: &[&Self],
|
||||
points: &[F],
|
||||
challenger: &mut Challenger<F>,
|
||||
) -> (OpeningProof<F>, Vec<Vec<F>>) {
|
||||
) -> (OpeningProof<F>, Vec<Vec<Vec<F>>>) {
|
||||
let degree = commitments[0].degree;
|
||||
assert!(
|
||||
commitments.iter().all(|c| c.degree == degree),
|
||||
@ -146,12 +146,14 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
||||
.map(|&x| {
|
||||
commitments
|
||||
.iter()
|
||||
.flat_map(move |c| c.polynomials.iter().map(|p| p.eval(x)).collect::<Vec<_>>())
|
||||
.map(move |c| c.polynomials.iter().map(|p| p.eval(x)).collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for evals in &evaluations {
|
||||
challenger.observe_elements(evals);
|
||||
for evals_per_point in &evaluations {
|
||||
for evals in evals_per_point {
|
||||
challenger.observe_elements(evals);
|
||||
}
|
||||
}
|
||||
|
||||
let alpha = challenger.get_challenge();
|
||||
@ -166,6 +168,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
||||
// Scale evaluations by `alpha`.
|
||||
let composition_evals = evaluations
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|e| reduce_with_powers(e, alpha))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -196,6 +199,28 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn batch_open_plonk(
|
||||
commitments: &[&Self; 5],
|
||||
points: &[F],
|
||||
challenger: &mut Challenger<F>,
|
||||
) -> (OpeningProof<F>, Vec<OpeningSet<F>>) {
|
||||
let (op, mut evaluations) = Self::batch_open(commitments, points, challenger);
|
||||
let opening_sets = evaluations
|
||||
.iter_mut()
|
||||
.map(|evals| {
|
||||
evals.reverse();
|
||||
OpeningSet {
|
||||
constants: evals.pop().unwrap(),
|
||||
plonk_sigmas: evals.pop().unwrap(),
|
||||
wires: evals.pop().unwrap(),
|
||||
plonk_zs: evals.pop().unwrap(),
|
||||
quotient_polys: evals.pop().unwrap(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
(op, opening_sets)
|
||||
}
|
||||
|
||||
/// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial
|
||||
/// `Q=(P-I)/Z` where `I` interpolates `(x_i, y_i)` and `Z` is the vanishing polynomial on `(x_i)`.
|
||||
fn compute_quotient(points: &[F], evals: &[F], poly: &Polynomial<F>) -> Polynomial<F> {
|
||||
|
||||
128
src/prover.rs
128
src/prover.rs
@ -20,53 +20,49 @@ use crate::vars::EvaluationVars;
|
||||
use crate::wire::Wire;
|
||||
use crate::witness::PartialWitness;
|
||||
|
||||
macro_rules! timed {
|
||||
($a:expr, $msg:expr) => {{
|
||||
let timer = Instant::now();
|
||||
let res = $a;
|
||||
info!("{:.3}s {}", timer.elapsed().as_secs_f32(), $msg);
|
||||
res
|
||||
}};
|
||||
}
|
||||
pub(crate) fn prove<F: Field>(
|
||||
prover_data: &ProverOnlyCircuitData<F>,
|
||||
common_data: &CommonCircuitData<F>,
|
||||
inputs: PartialWitness<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 fri_config = &common_data.config.fri_config;
|
||||
|
||||
let start_proof_gen = Instant::now();
|
||||
|
||||
let start_witness = Instant::now();
|
||||
let mut witness = inputs;
|
||||
info!("Running {} generators", prover_data.generators.len());
|
||||
generate_partial_witness(&mut witness, &prover_data.generators);
|
||||
info!(
|
||||
"{:.3}s to generate witness",
|
||||
start_witness.elapsed().as_secs_f32()
|
||||
timed!(
|
||||
generate_partial_witness(&mut witness, &prover_data.generators),
|
||||
"to generate witness"
|
||||
);
|
||||
|
||||
let config = common_data.config;
|
||||
let config = &common_data.config;
|
||||
let num_wires = config.num_wires;
|
||||
let num_checks = config.num_checks;
|
||||
let quotient_degree = common_data.quotient_degree();
|
||||
|
||||
let start_wire_ldes = Instant::now();
|
||||
let degree = common_data.degree();
|
||||
let wires_polynomials: Vec<PolynomialCoeffs<F>> = (0..num_wires)
|
||||
.into_par_iter()
|
||||
.map(|i| compute_wire_polynomial(i, &witness, degree))
|
||||
.collect();
|
||||
info!(
|
||||
"{:.3}s to compute wire LDEs",
|
||||
start_wire_ldes.elapsed().as_secs_f32()
|
||||
let wires_polynomials: Vec<PolynomialCoeffs<F>> = timed!(
|
||||
(0..num_wires)
|
||||
.into_par_iter()
|
||||
.map(|i| compute_wire_polynomial(i, &witness, degree))
|
||||
.collect(),
|
||||
"to compute wire polynomials"
|
||||
);
|
||||
|
||||
// TODO: Could try parallelizing the transpose, or not doing it explicitly, instead having
|
||||
// merkle_root_bit_rev_order do it implicitly.
|
||||
let start_wires_commitment = Instant::now();
|
||||
let wires_commitment = ListPolynomialCommitment::new(wires_polynomials, &fri_config);
|
||||
info!(
|
||||
"{:.3}s to transpose wire LDEs",
|
||||
start_wires_commitment.elapsed().as_secs_f32()
|
||||
let wires_commitment = timed!(
|
||||
ListPolynomialCommitment::new(wires_polynomials, &fri_config),
|
||||
"to compute wires commitment"
|
||||
);
|
||||
|
||||
let mut challenger = Challenger::new();
|
||||
@ -78,54 +74,44 @@ pub(crate) fn prove<F: Field>(
|
||||
let betas = challenger.get_n_challenges(num_checks);
|
||||
let gammas = challenger.get_n_challenges(num_checks);
|
||||
|
||||
let start_plonk_z = Instant::now();
|
||||
let plonk_z_vecs = compute_zs(&common_data);
|
||||
info!(
|
||||
"{:.3}s to compute Z's",
|
||||
start_plonk_z.elapsed().as_secs_f32()
|
||||
);
|
||||
let plonk_z_vecs = timed!(compute_zs(&common_data), "to compute Z's");
|
||||
|
||||
let start_plonk_z_root = Instant::now();
|
||||
let plonk_zs_commitment = ListPolynomialCommitment::new(plonk_z_vecs, &fri_config);
|
||||
info!(
|
||||
"{:.3}s to Merklize Z's",
|
||||
start_plonk_z_root.elapsed().as_secs_f32()
|
||||
let plonk_zs_commitment = timed!(
|
||||
ListPolynomialCommitment::new(plonk_z_vecs, &fri_config),
|
||||
"to commit to Z's"
|
||||
);
|
||||
|
||||
challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
|
||||
|
||||
let alphas = challenger.get_n_challenges(num_checks);
|
||||
|
||||
let start_vanishing_polys = Instant::now();
|
||||
let vanishing_polys = compute_vanishing_polys(
|
||||
common_data,
|
||||
prover_data,
|
||||
&wires_commitment.merkle_tree,
|
||||
&plonk_zs_commitment.merkle_tree,
|
||||
&betas,
|
||||
&gammas,
|
||||
&alphas,
|
||||
);
|
||||
info!(
|
||||
"{:.3}s to compute vanishing polys",
|
||||
start_vanishing_polys.elapsed().as_secs_f32()
|
||||
let vanishing_polys = timed!(
|
||||
compute_vanishing_polys(
|
||||
common_data,
|
||||
prover_data,
|
||||
&wires_commitment.merkle_tree,
|
||||
&plonk_zs_commitment.merkle_tree,
|
||||
&betas,
|
||||
&gammas,
|
||||
&alphas,
|
||||
),
|
||||
"to compute vanishing polys"
|
||||
);
|
||||
|
||||
// Compute the quotient polynomials, aka `t` in the Plonk paper.
|
||||
let quotient_polys_start = Instant::now();
|
||||
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);
|
||||
all_quotient_poly_chunks.extend(quotient_poly_coeff_chunks);
|
||||
}
|
||||
let quotient_polys_commitment =
|
||||
ListPolynomialCommitment::new(all_quotient_poly_chunks, &fri_config);
|
||||
info!(
|
||||
"{:.3}s to compute quotient polys and their LDEs",
|
||||
quotient_polys_start.elapsed().as_secs_f32()
|
||||
let quotient_polys_commitment = timed!(
|
||||
{
|
||||
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);
|
||||
all_quotient_poly_chunks.extend(quotient_poly_coeff_chunks);
|
||||
}
|
||||
ListPolynomialCommitment::new(all_quotient_poly_chunks, &fri_config)
|
||||
},
|
||||
"to compute quotient polys and commit to them"
|
||||
);
|
||||
|
||||
challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
|
||||
@ -149,10 +135,10 @@ pub(crate) fn prove<F: Field>(
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// TODO: This re-evaluates the polynomial and is thus redundant with the openings above.
|
||||
let fri_proofs = ListPolynomialCommitment::batch_open(
|
||||
let fri_proofs = ListPolynomialCommitment::batch_open_plonk(
|
||||
&[
|
||||
&todo!(),
|
||||
&todo!(),
|
||||
&prover_data.constants_commitment,
|
||||
&prover_data.sigmas_commitment,
|
||||
&wires_commitment,
|
||||
&plonk_zs_commitment,
|
||||
"ient_polys_commitment,
|
||||
@ -171,7 +157,7 @@ pub(crate) fn prove<F: Field>(
|
||||
plonk_zs_root: plonk_zs_commitment.merkle_tree.root,
|
||||
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
|
||||
openings,
|
||||
fri_proofs,
|
||||
fri_proofs: todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,10 +192,10 @@ fn compute_vanishing_polys<F: Field>(
|
||||
.map(|(i, x)| {
|
||||
let i_next = (i + 1) % lde_size;
|
||||
let local_wires = &wires_tree.leaves[i];
|
||||
let local_constants = &prover_data.constants_tree.leaves[i];
|
||||
let local_constants = &prover_data.constants_commitment.merkle_tree.leaves[i];
|
||||
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];
|
||||
let s_sigmas = &prover_data.sigmas_commitment.merkle_tree.leaves[i];
|
||||
|
||||
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
|
||||
debug_assert_eq!(local_plonk_zs.len(), num_checks);
|
||||
|
||||
@ -14,7 +14,7 @@ impl Target {
|
||||
Self::Wire(Wire { gate, input })
|
||||
}
|
||||
|
||||
pub fn is_routable(&self, config: CircuitConfig) -> bool {
|
||||
pub fn is_routable(&self, config: &CircuitConfig) -> bool {
|
||||
match self {
|
||||
Target::Wire(wire) => wire.is_routable(config),
|
||||
Target::PublicInput { .. } => true,
|
||||
|
||||
@ -10,7 +10,7 @@ pub struct Wire {
|
||||
}
|
||||
|
||||
impl Wire {
|
||||
pub fn is_routable(&self, config: CircuitConfig) -> bool {
|
||||
pub fn is_routable(&self, config: &CircuitConfig) -> bool {
|
||||
self.input < config.num_routed_wires
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user