Merge branch 'main' into extension-field

This commit is contained in:
wborgeaud 2021-05-11 15:28:25 +02:00
commit 75711f1d3f
12 changed files with 433 additions and 161 deletions

View File

@ -4,9 +4,11 @@ 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;
use plonky2::prover::PLONK_BLINDING;
use plonky2::witness::PartialWitness;
fn main() {
@ -34,11 +36,18 @@ fn bench_prove<F: Field>() {
security_bits: 128,
rate_bits: 3,
num_checks: 3,
fri_config: FriConfig {
proof_of_work_bits: 1,
rate_bits: 3,
reduction_arity_bits: vec![1],
num_query_rounds: 1,
blinding: PLONK_BLINDING.to_vec(),
},
};
let mut builder = CircuitBuilder::<F>::new(config);
for _ in 0..5000 {
for _ in 0..10000 {
builder.add_gate_no_constants(gmimc_gate.clone());
}

View File

@ -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,22 @@ 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.rate_bits,
false,
);
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.rate_bits,
false,
);
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 +296,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

View File

@ -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: vec![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.

View File

@ -5,7 +5,7 @@ pub mod verifier;
/// while increasing L, potentially requiring more challenge points.
const EPSILON: f64 = 0.01;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FriConfig {
pub proof_of_work_bits: u32,
@ -20,8 +20,9 @@ pub struct FriConfig {
/// Number of query rounds to perform.
pub num_query_rounds: usize,
/// True if the last element of the Merkle trees' leaf vectors is a blinding element.
pub blinding: bool,
/// Vector of the same length as the number of initial Merkle trees.
/// `blinding[i]==true` iff the i-th tree is salted.
pub blinding: Vec<bool>,
}
fn fri_delta(rate_log: usize, conjecture: bool) -> f64 {
@ -79,7 +80,7 @@ mod tests {
rate_bits,
proof_of_work_bits: 2,
reduction_arity_bits,
blinding: false,
blinding: vec![false],
};
let tree = {
let mut leaves = coset_lde
@ -92,7 +93,7 @@ mod tests {
};
let root = tree.root;
let mut challenger = Challenger::new();
let proof = fri_proof(&[tree], &coeffs, &coset_lde, &mut challenger, &config);
let proof = fri_proof(&[&tree], &coeffs, &coset_lde, &mut challenger, &config);
let mut challenger = Challenger::new();
verify_fri_proof(

View File

@ -10,7 +10,7 @@ use crate::util::reverse_index_bits_in_place;
/// Builds a FRI proof.
pub fn fri_proof<F: Field>(
initial_merkle_trees: &[MerkleTree<F>],
initial_merkle_trees: &[&MerkleTree<F>],
// Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero.
lde_polynomial_coeffs: &PolynomialCoeffs<F>,
// Evaluation of the polynomial on the large domain.
@ -113,7 +113,7 @@ fn fri_proof_of_work<F: Field>(current_hash: Hash<F>, config: &FriConfig) -> F {
}
fn fri_prover_query_rounds<F: Field>(
initial_merkle_trees: &[MerkleTree<F>],
initial_merkle_trees: &[&MerkleTree<F>],
trees: &[MerkleTree<F>],
challenger: &mut Challenger<F>,
n: usize,
@ -125,7 +125,7 @@ fn fri_prover_query_rounds<F: Field>(
}
fn fri_prover_query_round<F: Field>(
initial_merkle_trees: &[MerkleTree<F>],
initial_merkle_trees: &[&MerkleTree<F>],
trees: &[MerkleTree<F>],
challenger: &mut Challenger<F>,
n: usize,

View File

@ -4,6 +4,7 @@ use crate::fri::FriConfig;
use crate::hash::hash_n_to_1;
use crate::merkle_proofs::verify_merkle_proof;
use crate::plonk_challenger::Challenger;
use crate::polynomial::commitment::SALT_SIZE;
use crate::polynomial::polynomial::PolynomialCoeffs;
use crate::proof::{FriInitialTreeProof, FriProof, FriQueryRound, Hash};
use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place};
@ -148,10 +149,9 @@ fn fri_combine_initial<F: Field>(
let e = proof
.evals_proofs
.iter()
.map(|(v, _)| v)
.flatten()
.enumerate()
.flat_map(|(i, (v, _))| &v[..v.len() - if config.blinding[i] { SALT_SIZE } else { 0 }])
.rev()
.skip(if config.blinding { 2 } else { 0 }) // If blinding, the last two element are salt.
.fold(F::ZERO, |acc, &e| alpha * acc + e);
let numerator = e - interpolant.eval(subgroup_x);
let denominator = points.iter().map(|&(x, _)| subgroup_x - x).product();

View File

@ -6,33 +6,37 @@ 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;
use rayon::prelude::*;
struct ListPolynomialCommitment<F: Field> {
pub const SALT_SIZE: usize = 2;
pub struct ListPolynomialCommitment<F: Field> {
pub polynomials: Vec<PolynomialCoeffs<F>>,
pub fri_config: FriConfig,
pub merkle_tree: MerkleTree<F>,
pub degree: usize,
pub rate_bits: usize,
pub blinding: bool,
}
impl<F: Field> ListPolynomialCommitment<F> {
pub fn new(polynomials: Vec<PolynomialCoeffs<F>>, fri_config: &FriConfig) -> Self {
pub fn new(polynomials: Vec<PolynomialCoeffs<F>>, rate_bits: usize, blinding: bool) -> Self {
let degree = polynomials[0].len();
let lde_values = polynomials
.iter()
.par_iter()
.map(|p| {
assert_eq!(p.len(), degree, "Polynomial degree invalid.");
p.clone()
.lde(fri_config.rate_bits)
.lde(rate_bits)
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR)
.values
})
.chain(if fri_config.blinding {
.chain(if blinding {
// If blinding, salt with two random elements to each leaf vector.
(0..2)
.map(|_| F::rand_vec(degree << fri_config.rate_bits))
(0..SALT_SIZE)
.map(|_| F::rand_vec(degree << rate_bits))
.collect()
} else {
Vec::new()
@ -45,17 +49,27 @@ impl<F: Field> ListPolynomialCommitment<F> {
Self {
polynomials,
fri_config: fri_config.clone(),
merkle_tree,
degree,
rate_bits,
blinding,
}
}
pub fn leaf(&self, index: usize) -> &[F] {
let leaf = &self.merkle_tree.leaves[index];
&leaf[0..leaf.len() - if self.blinding { SALT_SIZE } else { 0 }]
}
pub fn open(
&self,
points: &[F],
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> (OpeningProof<F>, Vec<Vec<F>>) {
assert_eq!(self.rate_bits, config.rate_bits);
assert_eq!(config.blinding.len(), 1);
assert_eq!(self.blinding, config.blinding[0]);
for p in points {
assert_ne!(
p.exp_usize(self.degree),
@ -65,7 +79,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
}
let evaluations = points
.iter()
.par_iter()
.map(|&x| {
self.polynomials
.iter()
@ -88,23 +102,23 @@ impl<F: Field> ListPolynomialCommitment<F> {
.fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p));
// Scale evaluations by `alpha`.
let composition_evals = evaluations
.iter()
.par_iter()
.map(|e| reduce_with_powers(e, alpha))
.collect::<Vec<_>>();
let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly);
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.fri_config.rate_bits);
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(self.rate_bits);
let lde_quotient_values = lde_quotient
.clone()
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
let fri_proof = fri_proof(
&[self.merkle_tree.clone()],
&[&self.merkle_tree],
&lde_quotient,
&lde_quotient_values,
challenger,
&self.fri_config,
&config,
);
(
@ -116,6 +130,118 @@ impl<F: Field> ListPolynomialCommitment<F> {
)
}
pub fn batch_open(
commitments: &[&Self],
points: &[F],
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> (OpeningProof<F>, Vec<Vec<Vec<F>>>) {
let degree = commitments[0].degree;
assert_eq!(config.blinding.len(), commitments.len());
for (i, commitment) in commitments.iter().enumerate() {
assert_eq!(commitment.rate_bits, config.rate_bits, "Invalid rate.");
assert_eq!(
commitment.blinding, config.blinding[i],
"Invalid blinding paramater."
);
assert_eq!(
commitment.degree, degree,
"Trying to open polynomial commitments of different degrees."
);
}
for p in points {
assert_ne!(
p.exp_usize(degree),
F::ONE,
"Opening point is in the subgroup."
);
}
let evaluations = points
.par_iter()
.map(|&x| {
commitments
.iter()
.map(move |c| c.polynomials.iter().map(|p| p.eval(x)).collect::<Vec<_>>())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
for evals_per_point in &evaluations {
for evals in evals_per_point {
challenger.observe_elements(evals);
}
}
let alpha = challenger.get_challenge();
// Scale polynomials by `alpha`.
let composition_poly = commitments
.iter()
.flat_map(|c| &c.polynomials)
.rev()
.map(|p| p.clone().into())
.fold(Polynomial::empty(), |acc, p| acc.scalar_mul(alpha).add(&p));
// Scale evaluations by `alpha`.
let composition_evals = &evaluations
.par_iter()
.map(|v| {
v.iter()
.flatten()
.rev()
.fold(F::ZERO, |acc, &e| acc * alpha + e)
})
.collect::<Vec<_>>();
let quotient = Self::compute_quotient(points, &composition_evals, &composition_poly);
let lde_quotient = PolynomialCoeffs::from(quotient.clone()).lde(config.rate_bits);
let lde_quotient_values = lde_quotient
.clone()
.coset_fft(F::MULTIPLICATIVE_GROUP_GENERATOR);
let fri_proof = fri_proof(
&commitments
.par_iter()
.map(|c| &c.merkle_tree)
.collect::<Vec<_>>(),
&lde_quotient,
&lde_quotient_values,
challenger,
&config,
);
(
OpeningProof {
fri_proof,
quotient_degree: quotient.len(),
},
evaluations,
)
}
pub fn batch_open_plonk(
commitments: &[&Self; 5],
points: &[F],
challenger: &mut Challenger<F>,
config: &FriConfig,
) -> (OpeningProof<F>, Vec<OpeningSet<F>>) {
let (op, mut evaluations) = Self::batch_open(commitments, points, challenger, config);
let opening_sets = evaluations
.par_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> {
@ -151,20 +277,27 @@ impl<F: Field> OpeningProof<F> {
pub fn verify(
&self,
points: &[F],
evaluations: &[Vec<F>],
merkle_root: Hash<F>,
evaluations: &[Vec<Vec<F>>],
merkle_roots: &[Hash<F>],
challenger: &mut Challenger<F>,
fri_config: &FriConfig,
) -> Result<()> {
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();
let scaled_evals = evaluations
.iter()
.map(|e| reduce_with_powers(e, alpha))
.par_iter()
.map(|v| {
v.iter()
.flatten()
.rev()
.fold(F::ZERO, |acc, &e| acc * alpha + e)
})
.collect::<Vec<_>>();
let pairs = points
@ -177,7 +310,7 @@ impl<F: Field> OpeningProof<F> {
log2_strict(self.quotient_degree),
&pairs,
alpha,
&[merkle_root],
merkle_roots,
&self.fri_proof,
challenger,
fri_config,
@ -221,16 +354,16 @@ mod tests {
rate_bits: 2,
reduction_arity_bits: vec![3, 2, 1, 2],
num_query_rounds: 3,
blinding: false,
blinding: vec![false],
};
let (polys, points) = gen_random_test_case::<F>(k, degree_log, num_points);
let lpc = ListPolynomialCommitment::new(polys, &fri_config);
let (proof, evaluations) = lpc.open(&points, &mut Challenger::new());
let lpc = ListPolynomialCommitment::new(polys, fri_config.rate_bits, false);
let (proof, evaluations) = lpc.open(&points, &mut Challenger::new(), &fri_config);
proof.verify(
&points,
&evaluations,
lpc.merkle_tree.root,
&evaluations.into_iter().map(|e| vec![e]).collect::<Vec<_>>(),
&[lpc.merkle_tree.root],
&mut Challenger::new(),
&fri_config,
)
@ -248,16 +381,102 @@ mod tests {
rate_bits: 2,
reduction_arity_bits: vec![3, 2, 1, 2],
num_query_rounds: 3,
blinding: true,
blinding: vec![true],
};
let (polys, points) = gen_random_test_case::<F>(k, degree_log, num_points);
let lpc = ListPolynomialCommitment::new(polys, &fri_config);
let (proof, evaluations) = lpc.open(&points, &mut Challenger::new());
let lpc = ListPolynomialCommitment::new(polys, fri_config.rate_bits, true);
let (proof, evaluations) = lpc.open(&points, &mut Challenger::new(), &fri_config);
proof.verify(
&points,
&evaluations.into_iter().map(|e| vec![e]).collect::<Vec<_>>(),
&[lpc.merkle_tree.root],
&mut Challenger::new(),
&fri_config,
)
}
#[test]
fn test_batch_polynomial_commitment() -> Result<()> {
type F = CrandallField;
let k0 = 10;
let k1 = 3;
let k2 = 7;
let degree_log = 11;
let num_points = 5;
let fri_config = FriConfig {
proof_of_work_bits: 2,
rate_bits: 2,
reduction_arity_bits: vec![2, 3, 1, 2],
num_query_rounds: 3,
blinding: vec![false, false, false],
};
let (polys0, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
let (polys1, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
let (polys2, points) = gen_random_test_case::<F>(k0, degree_log, num_points);
let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, false);
let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false);
let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, false);
let (proof, evaluations) = ListPolynomialCommitment::batch_open(
&[&lpc0, &lpc1, &lpc2],
&points,
&mut Challenger::new(),
&fri_config,
);
proof.verify(
&points,
&evaluations,
lpc.merkle_tree.root,
&[
lpc0.merkle_tree.root,
lpc1.merkle_tree.root,
lpc2.merkle_tree.root,
],
&mut Challenger::new(),
&fri_config,
)
}
#[test]
fn test_batch_polynomial_commitment_blinding() -> Result<()> {
type F = CrandallField;
let k0 = 10;
let k1 = 3;
let k2 = 7;
let degree_log = 11;
let num_points = 5;
let fri_config = FriConfig {
proof_of_work_bits: 2,
rate_bits: 2,
reduction_arity_bits: vec![2, 3, 1, 2],
num_query_rounds: 3,
blinding: vec![true, false, true],
};
let (polys0, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
let (polys1, _) = gen_random_test_case::<F>(k0, degree_log, num_points);
let (polys2, points) = gen_random_test_case::<F>(k0, degree_log, num_points);
let lpc0 = ListPolynomialCommitment::new(polys0, fri_config.rate_bits, true);
let lpc1 = ListPolynomialCommitment::new(polys1, fri_config.rate_bits, false);
let lpc2 = ListPolynomialCommitment::new(polys2, fri_config.rate_bits, true);
let (proof, evaluations) = ListPolynomialCommitment::batch_open(
&[&lpc0, &lpc1, &lpc2],
&points,
&mut Challenger::new(),
&fri_config,
);
proof.verify(
&points,
&evaluations,
&[
lpc0.merkle_tree.root,
lpc1.merkle_tree.root,
lpc2.merkle_tree.root,
],
&mut Challenger::new(),
&fri_config,
)

View File

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

View File

@ -1,5 +1,6 @@
use crate::field::field::Field;
use crate::merkle_proofs::{MerkleProof, MerkleProofTarget};
use crate::polynomial::commitment::{ListPolynomialCommitment, OpeningProof};
use crate::polynomial::polynomial::PolynomialCoeffs;
use crate::target::Target;
use std::convert::TryInto;
@ -65,7 +66,7 @@ pub struct Proof<F: Field> {
pub openings: Vec<OpeningSet<F>>,
/// A FRI argument for each FRI query.
pub fri_proofs: Vec<FriProof<F>>,
pub opening_proof: OpeningProof<F>,
}
pub struct ProofTarget {
@ -136,6 +137,28 @@ pub struct OpeningSet<F: Field> {
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.
pub struct OpeningSetTarget {
pub constants: Vec<Target>,

View File

@ -4,67 +4,67 @@ use log::info;
use rayon::prelude::*;
use crate::circuit_data::{CommonCircuitData, ProverOnlyCircuitData};
use crate::field::fft::{fft, ifft};
use crate::field::fft::ifft;
use crate::field::field::Field;
use crate::generator::generate_partial_witness;
use crate::merkle_tree::MerkleTree;
use crate::plonk_challenger::Challenger;
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::polynomial::{PolynomialCoeffs, PolynomialValues};
use crate::proof::Proof;
use crate::util::{transpose, transpose_poly_values};
use crate::util::transpose;
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
}};
}
/// Corresponds to constants - sigmas - wires - zs - quotient — polynomial commitments.
pub const PLONK_BLINDING: [bool; 5] = [false, false, true, true, true];
pub(crate) fn prove<F: Field>(
prover_data: &ProverOnlyCircuitData<F>,
common_data: &CommonCircuitData<F>,
inputs: PartialWitness<F>,
) -> Proof<F> {
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 wire_ldes = (0..num_wires)
.into_par_iter()
.map(|i| compute_wire_lde(i, &witness, degree, config.rate_bits))
.collect::<Vec<_>>();
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_wire_transpose = Instant::now();
let wire_ldes_t = transpose_poly_values(wire_ldes);
info!(
"{:.3}s to transpose wire LDEs",
start_wire_transpose.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 wires_commitment = timed!(
ListPolynomialCommitment::new(wires_polynomials, fri_config.rate_bits, true),
"to compute wires commitment"
);
let mut challenger = Challenger::new();
@ -72,70 +72,71 @@ pub(crate) fn prove<F: Field>(
// TODO: Need to include public inputs as well.
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 gammas = challenger.get_n_challenges(num_checks);
let start_plonk_z = Instant::now();
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!(
"{:.3}s to compute Z's and their LDEs",
start_plonk_z.elapsed().as_secs_f32()
let plonk_z_vecs = timed!(compute_zs(&common_data), "to compute Z's");
let plonk_zs_commitment = timed!(
ListPolynomialCommitment::new(plonk_z_vecs, fri_config.rate_bits, true),
"to commit to Z's"
);
let start_plonk_z_root = Instant::now();
let plonk_zs_tree = MerkleTree::new(plonk_z_ldes_t, true);
info!(
"{:.3}s to Merklize Z's",
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 start_vanishing_polys = Instant::now();
let vanishing_polys = compute_vanishing_polys(
common_data,
prover_data,
&wires_tree,
&plonk_zs_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,
&plonk_zs_commitment,
&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_chunk_ldes = 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);
let quotient_poly_coeff_ldes =
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 =
MerkleTree::new(transpose_poly_values(all_quotient_poly_chunk_ldes), true);
challenger.observe_hash(&quotient_polys_tree.root);
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.rate_bits, true)
},
"to compute quotient polys and commit to them"
);
let openings = Vec::new(); // TODO
challenger.observe_hash(&quotient_polys_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 (opening_proof, openings) = timed!(
ListPolynomialCommitment::batch_open_plonk(
&[
&prover_data.constants_commitment,
&prover_data.sigmas_commitment,
&wires_commitment,
&plonk_zs_commitment,
&quotient_polys_commitment,
],
&zetas,
&mut challenger,
&common_data.config.fri_config
),
"to compute opening proofs"
);
info!(
"{:.3}s for overall witness & proof generation",
@ -143,30 +144,30 @@ pub(crate) fn prove<F: Field>(
);
Proof {
wires_root: wires_tree.root,
plonk_zs_root: plonk_zs_tree.root,
quotient_polys_root: quotient_polys_tree.root,
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,
openings,
fri_proofs,
opening_proof,
}
}
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)
.map(|i| compute_z(common_data, i))
.collect()
}
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, i: usize) -> PolynomialValues<F> {
PolynomialValues::zero(common_data.degree()) // TODO
fn compute_z<F: Field>(common_data: &CommonCircuitData<F>, _i: usize) -> PolynomialCoeffs<F> {
PolynomialCoeffs::zero(common_data.degree()) // TODO
}
// TODO: Parallelize.
fn compute_vanishing_polys<F: Field>(
common_data: &CommonCircuitData<F>,
prover_data: &ProverOnlyCircuitData<F>,
wires_tree: &MerkleTree<F>,
plonk_zs_tree: &MerkleTree<F>,
wires_commitment: &ListPolynomialCommitment<F>,
plonk_zs_commitment: &ListPolynomialCommitment<F>,
betas: &[F],
gammas: &[F],
alphas: &[F],
@ -181,11 +182,11 @@ fn compute_vanishing_polys<F: Field>(
.enumerate()
.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_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 local_wires = wires_commitment.leaf(i);
let local_constants = prover_data.constants_commitment.leaf(i);
let local_plonk_zs = plonk_zs_commitment.leaf(i);
let next_plonk_zs = plonk_zs_commitment.leaf(i_next);
let s_sigmas = prover_data.sigmas_commitment.leaf(i);
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
debug_assert_eq!(local_plonk_zs.len(), num_checks);
@ -264,12 +265,11 @@ fn compute_vanishing_poly_entry<F: Field>(
reduce_with_powers_multi(&vanishing_terms, alphas)
}
fn compute_wire_lde<F: Field>(
fn compute_wire_polynomial<F: Field>(
input: usize,
witness: &PartialWitness<F>,
degree: usize,
rate_bits: usize,
) -> PolynomialValues<F> {
) -> 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
@ -281,5 +281,5 @@ fn compute_wire_lde<F: Field>(
.unwrap_or(F::ZERO)
})
.collect();
PolynomialValues::new(wire_values).lde(rate_bits)
PolynomialValues::new(wire_values).ifft()
}

View File

@ -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,

View File

@ -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
}
}