mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-05 23:33:07 +00:00
Merge pull request #86 from mir-protocol/fix_z_check
Fix high degree `z` check by using partial products
This commit is contained in:
commit
c24fe65f44
@ -21,6 +21,7 @@ use crate::plonk_common::PlonkPolynomials;
|
|||||||
use crate::polynomial::commitment::ListPolynomialCommitment;
|
use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||||
use crate::polynomial::polynomial::PolynomialValues;
|
use crate::polynomial::polynomial::PolynomialValues;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
|
use crate::util::partial_products::num_partial_products;
|
||||||
use crate::util::{log2_ceil, log2_strict, transpose, transpose_poly_values};
|
use crate::util::{log2_ceil, log2_strict, transpose, transpose_poly_values};
|
||||||
use crate::wire::Wire;
|
use crate::wire::Wire;
|
||||||
|
|
||||||
@ -391,6 +392,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
/// Builds a "full circuit", with both prover and verifier data.
|
/// Builds a "full circuit", with both prover and verifier data.
|
||||||
pub fn build(mut self) -> CircuitData<F, D> {
|
pub fn build(mut self) -> CircuitData<F, D> {
|
||||||
|
let quotient_degree_factor = 7; // TODO: add this as a parameter.
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
info!(
|
info!(
|
||||||
"Degree before blinding & padding: {}",
|
"Degree before blinding & padding: {}",
|
||||||
@ -402,6 +404,10 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
let gates = self.gates.iter().cloned().collect();
|
let gates = self.gates.iter().cloned().collect();
|
||||||
let (gate_tree, max_filtered_constraint_degree, num_constants) = Tree::from_gates(gates);
|
let (gate_tree, max_filtered_constraint_degree, num_constants) = Tree::from_gates(gates);
|
||||||
|
assert!(
|
||||||
|
max_filtered_constraint_degree <= quotient_degree_factor + 1,
|
||||||
|
"Constraints are too high degree."
|
||||||
|
);
|
||||||
let prefixed_gates = PrefixedGate::from_tree(gate_tree);
|
let prefixed_gates = PrefixedGate::from_tree(gate_tree);
|
||||||
|
|
||||||
let degree_bits = log2_strict(degree);
|
let degree_bits = log2_strict(degree);
|
||||||
@ -444,6 +450,9 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
.max()
|
.max()
|
||||||
.expect("No gates?");
|
.expect("No gates?");
|
||||||
|
|
||||||
|
let num_partial_products =
|
||||||
|
num_partial_products(self.config.num_routed_wires, quotient_degree_factor);
|
||||||
|
|
||||||
// TODO: This should also include an encoding of gate constraints.
|
// TODO: This should also include an encoding of gate constraints.
|
||||||
let circuit_digest_parts = [
|
let circuit_digest_parts = [
|
||||||
constants_sigmas_root.elements.to_vec(),
|
constants_sigmas_root.elements.to_vec(),
|
||||||
@ -455,10 +464,11 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
config: self.config,
|
config: self.config,
|
||||||
degree_bits,
|
degree_bits,
|
||||||
gates: prefixed_gates,
|
gates: prefixed_gates,
|
||||||
max_filtered_constraint_degree,
|
quotient_degree_factor,
|
||||||
num_gate_constraints,
|
num_gate_constraints,
|
||||||
num_constants,
|
num_constants,
|
||||||
k_is,
|
k_is,
|
||||||
|
num_partial_products,
|
||||||
circuit_digest,
|
circuit_digest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::ops::Range;
|
use std::ops::{Range, RangeFrom};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
@ -145,8 +145,8 @@ pub struct CommonCircuitData<F: Extendable<D>, const D: usize> {
|
|||||||
/// The types of gates used in this circuit, along with their prefixes.
|
/// The types of gates used in this circuit, along with their prefixes.
|
||||||
pub(crate) gates: Vec<PrefixedGate<F, D>>,
|
pub(crate) gates: Vec<PrefixedGate<F, D>>,
|
||||||
|
|
||||||
/// The maximum degree of a filter times a constraint by any gate.
|
/// The degree of the PLONK quotient polynomial.
|
||||||
pub(crate) max_filtered_constraint_degree: usize,
|
pub(crate) quotient_degree_factor: usize,
|
||||||
|
|
||||||
/// The largest number of constraints imposed by any gate.
|
/// The largest number of constraints imposed by any gate.
|
||||||
pub(crate) num_gate_constraints: usize,
|
pub(crate) num_gate_constraints: usize,
|
||||||
@ -157,6 +157,10 @@ pub struct CommonCircuitData<F: Extendable<D>, const D: usize> {
|
|||||||
/// The `{k_i}` valued used in `S_ID_i` in Plonk's permutation argument.
|
/// The `{k_i}` valued used in `S_ID_i` in Plonk's permutation argument.
|
||||||
pub(crate) k_is: Vec<F>,
|
pub(crate) k_is: Vec<F>,
|
||||||
|
|
||||||
|
/// The number of partial products needed to compute the `Z` polynomials and the number
|
||||||
|
/// of partial products needed to compute the final product.
|
||||||
|
pub(crate) num_partial_products: (usize, usize),
|
||||||
|
|
||||||
/// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to
|
/// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to
|
||||||
/// seed Fiat-Shamir.
|
/// seed Fiat-Shamir.
|
||||||
pub(crate) circuit_digest: Hash<F>,
|
pub(crate) circuit_digest: Hash<F>,
|
||||||
@ -184,7 +188,7 @@ impl<F: Extendable<D>, const D: usize> CommonCircuitData<F, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn quotient_degree(&self) -> usize {
|
pub fn quotient_degree(&self) -> usize {
|
||||||
(self.max_filtered_constraint_degree - 1) * self.degree()
|
self.quotient_degree_factor * self.degree()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_constraints(&self) -> usize {
|
pub fn total_constraints(&self) -> usize {
|
||||||
@ -201,6 +205,16 @@ impl<F: Extendable<D>, const D: usize> CommonCircuitData<F, D> {
|
|||||||
pub fn sigmas_range(&self) -> Range<usize> {
|
pub fn sigmas_range(&self) -> Range<usize> {
|
||||||
self.num_constants..self.num_constants + self.config.num_routed_wires
|
self.num_constants..self.num_constants + self.config.num_routed_wires
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Range of the `z`s polynomials in the `zs_partial_products_commitment`.
|
||||||
|
pub fn zs_range(&self) -> Range<usize> {
|
||||||
|
0..self.config.num_challenges
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Range of the partial products polynomials in the `zs_partial_products_commitment`.
|
||||||
|
pub fn partial_products_range(&self) -> RangeFrom<usize> {
|
||||||
|
self.config.num_challenges..
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `Target` version of `VerifierCircuitData`, for use inside recursive circuits. Note that this
|
/// The `Target` version of `VerifierCircuitData`, for use inside recursive circuits. Note that this
|
||||||
|
|||||||
@ -183,7 +183,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
// Polynomials opened at `x` and `g x`, i.e., the Zs polynomials.
|
// Polynomials opened at `x` and `g x`, i.e., the Zs polynomials.
|
||||||
let zs_evals = proof
|
let zs_evals = proof
|
||||||
.unsalted_evals(PlonkPolynomials::ZS)
|
.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&e| self.convert_to_ext(e))
|
.map(|&e| self.convert_to_ext(e))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use anyhow::{ensure, Result};
|
use anyhow::{ensure, Result};
|
||||||
|
|
||||||
|
use crate::circuit_data::CommonCircuitData;
|
||||||
use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius};
|
use crate::field::extension_field::{flatten, Extendable, FieldExtension, Frobenius};
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::field::interpolation::{barycentric_weights, interpolate, interpolate2};
|
use crate::field::interpolation::{barycentric_weights, interpolate, interpolate2};
|
||||||
@ -75,8 +76,9 @@ pub fn verify_fri_proof<F: Field + Extendable<D>, const D: usize>(
|
|||||||
initial_merkle_roots: &[Hash<F>],
|
initial_merkle_roots: &[Hash<F>],
|
||||||
proof: &FriProof<F, D>,
|
proof: &FriProof<F, D>,
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
config: &FriConfig,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let config = &common_data.config.fri_config;
|
||||||
let total_arities = config.reduction_arity_bits.iter().sum::<usize>();
|
let total_arities = config.reduction_arity_bits.iter().sum::<usize>();
|
||||||
ensure!(
|
ensure!(
|
||||||
purported_degree_log
|
purported_degree_log
|
||||||
@ -122,7 +124,7 @@ pub fn verify_fri_proof<F: Field + Extendable<D>, const D: usize>(
|
|||||||
n,
|
n,
|
||||||
&betas,
|
&betas,
|
||||||
round_proof,
|
round_proof,
|
||||||
config,
|
common_data,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,8 +149,9 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
|||||||
os: &OpeningSet<F, D>,
|
os: &OpeningSet<F, D>,
|
||||||
zeta: F::Extension,
|
zeta: F::Extension,
|
||||||
subgroup_x: F,
|
subgroup_x: F,
|
||||||
config: &FriConfig,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> F::Extension {
|
) -> F::Extension {
|
||||||
|
let config = &common_data.config.fri_config;
|
||||||
assert!(D > 1, "Not implemented for D=1.");
|
assert!(D > 1, "Not implemented for D=1.");
|
||||||
let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits;
|
let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits;
|
||||||
let subgroup_x = F::Extension::from_basefield(subgroup_x);
|
let subgroup_x = F::Extension::from_basefield(subgroup_x);
|
||||||
@ -167,12 +170,17 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
|||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|&p| proof.unsalted_evals(p))
|
.flat_map(|&p| proof.unsalted_evals(p))
|
||||||
|
.chain(
|
||||||
|
&proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS)
|
||||||
|
[common_data.partial_products_range()],
|
||||||
|
)
|
||||||
.map(|&e| F::Extension::from_basefield(e));
|
.map(|&e| F::Extension::from_basefield(e));
|
||||||
let single_openings = os
|
let single_openings = os
|
||||||
.constants
|
.constants
|
||||||
.iter()
|
.iter()
|
||||||
.chain(&os.plonk_s_sigmas)
|
.chain(&os.plonk_s_sigmas)
|
||||||
.chain(&os.quotient_polys);
|
.chain(&os.quotient_polys)
|
||||||
|
.chain(&os.partial_products);
|
||||||
let single_diffs = single_evals
|
let single_diffs = single_evals
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(single_openings)
|
.zip(single_openings)
|
||||||
@ -185,9 +193,10 @@ fn fri_combine_initial<F: Field + Extendable<D>, const D: usize>(
|
|||||||
|
|
||||||
// Polynomials opened at `x` and `g x`, i.e., the Zs polynomials.
|
// Polynomials opened at `x` and `g x`, i.e., the Zs polynomials.
|
||||||
let zs_evals = proof
|
let zs_evals = proof
|
||||||
.unsalted_evals(PlonkPolynomials::ZS)
|
.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&e| F::Extension::from_basefield(e));
|
.map(|&e| F::Extension::from_basefield(e))
|
||||||
|
.take(common_data.zs_range().end);
|
||||||
let zs_composition_eval = alpha.clone().reduce(zs_evals);
|
let zs_composition_eval = alpha.clone().reduce(zs_evals);
|
||||||
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
|
let zeta_right = F::Extension::primitive_root_of_unity(degree_log) * zeta;
|
||||||
let zs_interpol = interpolate2(
|
let zs_interpol = interpolate2(
|
||||||
@ -236,8 +245,9 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
n: usize,
|
n: usize,
|
||||||
betas: &[F::Extension],
|
betas: &[F::Extension],
|
||||||
round_proof: &FriQueryRound<F, D>,
|
round_proof: &FriQueryRound<F, D>,
|
||||||
config: &FriConfig,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let config = &common_data.config.fri_config;
|
||||||
let mut evaluations: Vec<Vec<F::Extension>> = Vec::new();
|
let mut evaluations: Vec<Vec<F::Extension>> = Vec::new();
|
||||||
let x = challenger.get_challenge();
|
let x = challenger.get_challenge();
|
||||||
let mut domain_size = n;
|
let mut domain_size = n;
|
||||||
@ -262,7 +272,7 @@ fn fri_verifier_query_round<F: Field + Extendable<D>, const D: usize>(
|
|||||||
os,
|
os,
|
||||||
zeta,
|
zeta,
|
||||||
subgroup_x,
|
subgroup_x,
|
||||||
config,
|
common_data,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let last_evals = &evaluations[i - 1];
|
let last_evals = &evaluations[i - 1];
|
||||||
|
|||||||
@ -438,6 +438,7 @@ mod tests {
|
|||||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::fri::FriConfig;
|
use crate::fri::FriConfig;
|
||||||
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -461,5 +462,7 @@ mod tests {
|
|||||||
|
|
||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,6 +79,7 @@ mod tests {
|
|||||||
use crate::field::crandall_field::CrandallField;
|
use crate::field::crandall_field::CrandallField;
|
||||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
fn real_insert<const D: usize>(
|
fn real_insert<const D: usize>(
|
||||||
@ -116,6 +117,8 @@ mod tests {
|
|||||||
|
|
||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -66,6 +66,7 @@ mod tests {
|
|||||||
use crate::field::extension_field::FieldExtension;
|
use crate::field::extension_field::FieldExtension;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
use crate::field::interpolation::{interpolant, interpolate};
|
use crate::field::interpolation::{interpolant, interpolate};
|
||||||
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -103,6 +104,8 @@ mod tests {
|
|||||||
|
|
||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -135,5 +138,7 @@ mod tests {
|
|||||||
|
|
||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,6 +118,7 @@ mod tests {
|
|||||||
use crate::field::crandall_field::CrandallField;
|
use crate::field::crandall_field::CrandallField;
|
||||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
fn real_rotate<const D: usize>(
|
fn real_rotate<const D: usize>(
|
||||||
@ -150,6 +151,8 @@ mod tests {
|
|||||||
|
|
||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -41,6 +41,7 @@ mod tests {
|
|||||||
use crate::circuit_data::CircuitConfig;
|
use crate::circuit_data::CircuitConfig;
|
||||||
use crate::field::crandall_field::CrandallField;
|
use crate::field::crandall_field::CrandallField;
|
||||||
use crate::field::field::Field;
|
use crate::field::field::Field;
|
||||||
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -67,5 +68,7 @@ mod tests {
|
|||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
|
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,7 +74,7 @@ impl<F: Extendable<D>, const D: usize> Tree<GateRef<F, D>> {
|
|||||||
// Iterate backwards from `max_degree` to try to find a tree with a lower degree
|
// Iterate backwards from `max_degree` to try to find a tree with a lower degree
|
||||||
// but the same number of constants.
|
// but the same number of constants.
|
||||||
'optdegree: for degree in (0..max_degree).rev() {
|
'optdegree: for degree in (0..max_degree).rev() {
|
||||||
if let Some(mut tree) = Self::find_tree(&gates, degree, max_constants) {
|
if let Some(tree) = Self::find_tree(&gates, degree, max_constants) {
|
||||||
let num_constants = tree.num_constants();
|
let num_constants = tree.num_constants();
|
||||||
if num_constants > best_num_constants {
|
if num_constants > best_num_constants {
|
||||||
break 'optdegree;
|
break 'optdegree;
|
||||||
|
|||||||
@ -72,6 +72,7 @@ impl<F: Field> Challenger<F> {
|
|||||||
wires,
|
wires,
|
||||||
plonk_zs,
|
plonk_zs,
|
||||||
plonk_zs_right,
|
plonk_zs_right,
|
||||||
|
partial_products,
|
||||||
quotient_polys,
|
quotient_polys,
|
||||||
} = os;
|
} = os;
|
||||||
for v in &[
|
for v in &[
|
||||||
@ -80,6 +81,7 @@ impl<F: Field> Challenger<F> {
|
|||||||
wires,
|
wires,
|
||||||
plonk_zs,
|
plonk_zs,
|
||||||
plonk_zs_right,
|
plonk_zs_right,
|
||||||
|
partial_products,
|
||||||
quotient_polys,
|
quotient_polys,
|
||||||
] {
|
] {
|
||||||
self.observe_extension_elements(v);
|
self.observe_extension_elements(v);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use crate::gates::gate::{GateRef, PrefixedGate};
|
|||||||
use crate::polynomial::commitment::SALT_SIZE;
|
use crate::polynomial::commitment::SALT_SIZE;
|
||||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||||
use crate::target::Target;
|
use crate::target::Target;
|
||||||
|
use crate::util::partial_products::check_partial_products;
|
||||||
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
|
use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
|
||||||
|
|
||||||
/// Holds the Merkle tree index and blinding flag of a set of polynomials used in FRI.
|
/// Holds the Merkle tree index and blinding flag of a set of polynomials used in FRI.
|
||||||
@ -37,7 +38,7 @@ impl PlonkPolynomials {
|
|||||||
index: 1,
|
index: 1,
|
||||||
blinding: true,
|
blinding: true,
|
||||||
};
|
};
|
||||||
pub const ZS: PolynomialsIndexBlinding = PolynomialsIndexBlinding {
|
pub const ZS_PARTIAL_PRODUCTS: PolynomialsIndexBlinding = PolynomialsIndexBlinding {
|
||||||
index: 2,
|
index: 2,
|
||||||
blinding: true,
|
blinding: true,
|
||||||
};
|
};
|
||||||
@ -50,7 +51,7 @@ impl PlonkPolynomials {
|
|||||||
match i {
|
match i {
|
||||||
0 => Self::CONSTANTS_SIGMAS,
|
0 => Self::CONSTANTS_SIGMAS,
|
||||||
1 => Self::WIRES,
|
1 => Self::WIRES,
|
||||||
2 => Self::ZS,
|
2 => Self::ZS_PARTIAL_PRODUCTS,
|
||||||
3 => Self::QUOTIENT,
|
3 => Self::QUOTIENT,
|
||||||
_ => panic!("There are only 4 sets of polynomials in Plonk."),
|
_ => panic!("There are only 4 sets of polynomials in Plonk."),
|
||||||
}
|
}
|
||||||
@ -64,41 +65,80 @@ pub(crate) fn eval_vanishing_poly<F: Extendable<D>, const D: usize>(
|
|||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
x: F::Extension,
|
x: F::Extension,
|
||||||
vars: EvaluationVars<F, D>,
|
vars: EvaluationVars<F, D>,
|
||||||
local_plonk_zs: &[F::Extension],
|
local_zs: &[F::Extension],
|
||||||
next_plonk_zs: &[F::Extension],
|
next_zs: &[F::Extension],
|
||||||
|
partial_products: &[F::Extension],
|
||||||
s_sigmas: &[F::Extension],
|
s_sigmas: &[F::Extension],
|
||||||
betas: &[F],
|
betas: &[F],
|
||||||
gammas: &[F],
|
gammas: &[F],
|
||||||
alphas: &[F],
|
alphas: &[F],
|
||||||
) -> Vec<F::Extension> {
|
) -> Vec<F::Extension> {
|
||||||
|
let partial_products_degree = common_data.quotient_degree_factor;
|
||||||
|
let (num_prods, final_num_prod) = common_data.num_partial_products;
|
||||||
|
|
||||||
let constraint_terms =
|
let constraint_terms =
|
||||||
evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars);
|
evaluate_gate_constraints(&common_data.gates, common_data.num_gate_constraints, vars);
|
||||||
|
|
||||||
// The L_1(x) (Z(x) - 1) vanishing terms.
|
// The L_1(x) (Z(x) - 1) vanishing terms.
|
||||||
let mut vanishing_z_1_terms = Vec::new();
|
let mut vanishing_z_1_terms = Vec::new();
|
||||||
|
// The terms checking the partial products.
|
||||||
|
let mut vanishing_partial_products_terms = Vec::new();
|
||||||
// The Z(x) f'(x) - g'(x) Z(g x) terms.
|
// The Z(x) f'(x) - g'(x) Z(g x) terms.
|
||||||
let mut vanishing_v_shift_terms = Vec::new();
|
let mut vanishing_v_shift_terms = Vec::new();
|
||||||
|
|
||||||
for i in 0..common_data.config.num_challenges {
|
for i in 0..common_data.config.num_challenges {
|
||||||
let z_x = local_plonk_zs[i];
|
let z_x = local_zs[i];
|
||||||
let z_gz = next_plonk_zs[i];
|
let z_gz = next_zs[i];
|
||||||
vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::Extension::ONE));
|
vanishing_z_1_terms.push(eval_l_1(common_data.degree(), x) * (z_x - F::Extension::ONE));
|
||||||
|
|
||||||
let mut f_prime = F::Extension::ONE;
|
let numerator_values = (0..common_data.config.num_routed_wires)
|
||||||
let mut g_prime = F::Extension::ONE;
|
.map(|j| {
|
||||||
for j in 0..common_data.config.num_routed_wires {
|
let wire_value = vars.local_wires[j];
|
||||||
let wire_value = vars.local_wires[j];
|
let k_i = common_data.k_is[j];
|
||||||
let k_i = common_data.k_is[j];
|
let s_id = x * k_i.into();
|
||||||
let s_id = x * k_i.into();
|
wire_value + s_id * betas[i].into() + gammas[i].into()
|
||||||
let s_sigma = s_sigmas[j];
|
})
|
||||||
f_prime *= wire_value + s_id * betas[i].into() + gammas[i].into();
|
.collect::<Vec<_>>();
|
||||||
g_prime *= wire_value + s_sigma * betas[i].into() + gammas[i].into();
|
let denominator_values = (0..common_data.config.num_routed_wires)
|
||||||
}
|
.map(|j| {
|
||||||
vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz);
|
let wire_value = vars.local_wires[j];
|
||||||
|
let s_sigma = s_sigmas[j];
|
||||||
|
wire_value + s_sigma * betas[i].into() + gammas[i].into()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let quotient_values = (0..common_data.config.num_routed_wires)
|
||||||
|
.map(|j| numerator_values[j] / denominator_values[j])
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// The partial products considered for this iteration of `i`.
|
||||||
|
let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods];
|
||||||
|
// Check the quotient partial products.
|
||||||
|
let mut partial_product_check = check_partial_products(
|
||||||
|
"ient_values,
|
||||||
|
current_partial_products,
|
||||||
|
partial_products_degree,
|
||||||
|
);
|
||||||
|
// The first checks are of the form `q - n/d` which is a rational function not a polynomial.
|
||||||
|
// We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials.
|
||||||
|
denominator_values
|
||||||
|
.chunks(partial_products_degree)
|
||||||
|
.zip(partial_product_check.iter_mut())
|
||||||
|
.for_each(|(d, q)| {
|
||||||
|
*q *= d.iter().copied().product();
|
||||||
|
});
|
||||||
|
vanishing_partial_products_terms.extend(partial_product_check);
|
||||||
|
|
||||||
|
// The quotient final product is the product of the last `final_num_prod` elements.
|
||||||
|
let quotient: F::Extension = current_partial_products[num_prods - final_num_prod..]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.product();
|
||||||
|
vanishing_v_shift_terms.push(quotient * z_x - z_gz);
|
||||||
}
|
}
|
||||||
|
|
||||||
let vanishing_terms = [
|
let vanishing_terms = [
|
||||||
vanishing_z_1_terms,
|
vanishing_z_1_terms,
|
||||||
|
vanishing_partial_products_terms,
|
||||||
vanishing_v_shift_terms,
|
vanishing_v_shift_terms,
|
||||||
constraint_terms,
|
constraint_terms,
|
||||||
]
|
]
|
||||||
@ -114,42 +154,80 @@ pub(crate) fn eval_vanishing_poly_base<F: Extendable<D>, const D: usize>(
|
|||||||
index: usize,
|
index: usize,
|
||||||
x: F,
|
x: F,
|
||||||
vars: EvaluationVarsBase<F>,
|
vars: EvaluationVarsBase<F>,
|
||||||
local_plonk_zs: &[F],
|
local_zs: &[F],
|
||||||
next_plonk_zs: &[F],
|
next_zs: &[F],
|
||||||
|
partial_products: &[F],
|
||||||
s_sigmas: &[F],
|
s_sigmas: &[F],
|
||||||
betas: &[F],
|
betas: &[F],
|
||||||
gammas: &[F],
|
gammas: &[F],
|
||||||
alphas: &[F],
|
alphas: &[F],
|
||||||
z_h_on_coset: &ZeroPolyOnCoset<F>,
|
z_h_on_coset: &ZeroPolyOnCoset<F>,
|
||||||
) -> Vec<F> {
|
) -> Vec<F> {
|
||||||
|
let partial_products_degree = common_data.quotient_degree_factor;
|
||||||
|
let (num_prods, final_num_prod) = common_data.num_partial_products;
|
||||||
|
|
||||||
let constraint_terms =
|
let constraint_terms =
|
||||||
evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars);
|
evaluate_gate_constraints_base(&common_data.gates, common_data.num_gate_constraints, vars);
|
||||||
|
|
||||||
// The L_1(x) (Z(x) - 1) vanishing terms.
|
// The L_1(x) (Z(x) - 1) vanishing terms.
|
||||||
let mut vanishing_z_1_terms = Vec::new();
|
let mut vanishing_z_1_terms = Vec::new();
|
||||||
|
// The terms checking the partial products.
|
||||||
|
let mut vanishing_partial_products_terms = Vec::new();
|
||||||
// The Z(x) f'(x) - g'(x) Z(g x) terms.
|
// The Z(x) f'(x) - g'(x) Z(g x) terms.
|
||||||
let mut vanishing_v_shift_terms = Vec::new();
|
let mut vanishing_v_shift_terms = Vec::new();
|
||||||
|
|
||||||
for i in 0..common_data.config.num_challenges {
|
for i in 0..common_data.config.num_challenges {
|
||||||
let z_x = local_plonk_zs[i];
|
let z_x = local_zs[i];
|
||||||
let z_gz = next_plonk_zs[i];
|
let z_gz = next_zs[i];
|
||||||
vanishing_z_1_terms.push(z_h_on_coset.eval_l1(index, x) * (z_x - F::ONE));
|
vanishing_z_1_terms.push(z_h_on_coset.eval_l1(index, x) * (z_x - F::ONE));
|
||||||
|
|
||||||
let mut f_prime = F::ONE;
|
let numerator_values = (0..common_data.config.num_routed_wires)
|
||||||
let mut g_prime = F::ONE;
|
.map(|j| {
|
||||||
for j in 0..common_data.config.num_routed_wires {
|
let wire_value = vars.local_wires[j];
|
||||||
let wire_value = vars.local_wires[j];
|
let k_i = common_data.k_is[j];
|
||||||
let k_i = common_data.k_is[j];
|
let s_id = k_i * x;
|
||||||
let s_id = k_i * x;
|
wire_value + betas[i] * s_id + gammas[i]
|
||||||
let s_sigma = s_sigmas[j];
|
})
|
||||||
f_prime *= wire_value + betas[i] * s_id + gammas[i];
|
.collect::<Vec<_>>();
|
||||||
g_prime *= wire_value + betas[i] * s_sigma + gammas[i];
|
let denominator_values = (0..common_data.config.num_routed_wires)
|
||||||
}
|
.map(|j| {
|
||||||
vanishing_v_shift_terms.push(f_prime * z_x - g_prime * z_gz);
|
let wire_value = vars.local_wires[j];
|
||||||
}
|
let s_sigma = s_sigmas[j];
|
||||||
|
wire_value + betas[i] * s_sigma + gammas[i]
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let quotient_values = (0..common_data.config.num_routed_wires)
|
||||||
|
.map(|j| numerator_values[j] / denominator_values[j])
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// The partial products considered for this iteration of `i`.
|
||||||
|
let current_partial_products = &partial_products[i * num_prods..(i + 1) * num_prods];
|
||||||
|
// Check the quotient partial products.
|
||||||
|
let mut partial_product_check = check_partial_products(
|
||||||
|
"ient_values,
|
||||||
|
current_partial_products,
|
||||||
|
partial_products_degree,
|
||||||
|
);
|
||||||
|
// The first checks are of the form `q - n/d` which is a rational function not a polynomial.
|
||||||
|
// We multiply them by `d` to get checks of the form `q*d - n` which low-degree polynomials.
|
||||||
|
denominator_values
|
||||||
|
.chunks(partial_products_degree)
|
||||||
|
.zip(partial_product_check.iter_mut())
|
||||||
|
.for_each(|(d, q)| {
|
||||||
|
*q *= d.iter().copied().product();
|
||||||
|
});
|
||||||
|
vanishing_partial_products_terms.extend(partial_product_check);
|
||||||
|
|
||||||
|
// The quotient final product is the product of the last `final_num_prod` elements.
|
||||||
|
let quotient: F = current_partial_products[num_prods - final_num_prod..]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.product();
|
||||||
|
vanishing_v_shift_terms.push(quotient * z_x - z_gz);
|
||||||
|
}
|
||||||
let vanishing_terms = [
|
let vanishing_terms = [
|
||||||
vanishing_z_1_terms,
|
vanishing_z_1_terms,
|
||||||
|
vanishing_partial_products_terms,
|
||||||
vanishing_v_shift_terms,
|
vanishing_v_shift_terms,
|
||||||
constraint_terms,
|
constraint_terms,
|
||||||
]
|
]
|
||||||
|
|||||||
@ -147,6 +147,13 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
// Final low-degree polynomial that goes into FRI.
|
// Final low-degree polynomial that goes into FRI.
|
||||||
let mut final_poly = PolynomialCoeffs::empty();
|
let mut final_poly = PolynomialCoeffs::empty();
|
||||||
|
|
||||||
|
let mut zs_polys = commitments[PlonkPolynomials::ZS_PARTIAL_PRODUCTS.index]
|
||||||
|
.polynomials
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.to_extension())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let partial_products_polys = zs_polys.split_off(common_data.zs_range().end);
|
||||||
|
|
||||||
// Polynomials opened at a single point.
|
// Polynomials opened at a single point.
|
||||||
let single_polys = [
|
let single_polys = [
|
||||||
PlonkPolynomials::CONSTANTS_SIGMAS,
|
PlonkPolynomials::CONSTANTS_SIGMAS,
|
||||||
@ -154,7 +161,8 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|&p| &commitments[p.index].polynomials)
|
.flat_map(|&p| &commitments[p.index].polynomials)
|
||||||
.map(|p| p.to_extension());
|
.map(|p| p.to_extension())
|
||||||
|
.chain(partial_products_polys);
|
||||||
let single_composition_poly = alpha.reduce_polys(single_polys);
|
let single_composition_poly = alpha.reduce_polys(single_polys);
|
||||||
|
|
||||||
let single_quotient = Self::compute_quotient([zeta], single_composition_poly);
|
let single_quotient = Self::compute_quotient([zeta], single_composition_poly);
|
||||||
@ -162,11 +170,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
|
|||||||
alpha.reset();
|
alpha.reset();
|
||||||
|
|
||||||
// Zs polynomials are opened at `zeta` and `g*zeta`.
|
// Zs polynomials are opened at `zeta` and `g*zeta`.
|
||||||
let zs_polys = commitments[PlonkPolynomials::ZS.index]
|
let zs_composition_poly = alpha.reduce_polys(zs_polys.into_iter());
|
||||||
.polynomials
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.to_extension());
|
|
||||||
let zs_composition_poly = alpha.reduce_polys(zs_polys);
|
|
||||||
|
|
||||||
let zs_quotient = Self::compute_quotient([zeta, g * zeta], zs_composition_poly);
|
let zs_quotient = Self::compute_quotient([zeta, g * zeta], zs_composition_poly);
|
||||||
alpha.shift_poly(&mut final_poly);
|
alpha.shift_poly(&mut final_poly);
|
||||||
@ -254,7 +258,7 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
|
|||||||
os: &OpeningSet<F, D>,
|
os: &OpeningSet<F, D>,
|
||||||
merkle_roots: &[Hash<F>],
|
merkle_roots: &[Hash<F>],
|
||||||
challenger: &mut Challenger<F>,
|
challenger: &mut Challenger<F>,
|
||||||
fri_config: &FriConfig,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
challenger.observe_opening_set(os);
|
challenger.observe_opening_set(os);
|
||||||
|
|
||||||
@ -268,7 +272,7 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningProof<F, D> {
|
|||||||
merkle_roots,
|
merkle_roots,
|
||||||
&self.fri_proof,
|
&self.fri_proof,
|
||||||
challenger,
|
challenger,
|
||||||
fri_config,
|
common_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +314,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_batch_polynomial_commitment<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
|
fn check_batch_polynomial_commitment<F: Field + Extendable<D>, const D: usize>() -> Result<()> {
|
||||||
let ks = [10, 2, 3, 8];
|
let ks = [10, 2, 10, 8];
|
||||||
let degree_log = 11;
|
let degree_log = 11;
|
||||||
let fri_config = FriConfig {
|
let fri_config = FriConfig {
|
||||||
proof_of_work_bits: 2,
|
proof_of_work_bits: 2,
|
||||||
@ -327,10 +331,11 @@ mod tests {
|
|||||||
},
|
},
|
||||||
degree_bits: 0,
|
degree_bits: 0,
|
||||||
gates: vec![],
|
gates: vec![],
|
||||||
max_filtered_constraint_degree: 0,
|
quotient_degree_factor: 0,
|
||||||
num_gate_constraints: 0,
|
num_gate_constraints: 0,
|
||||||
num_constants: 4,
|
num_constants: 4,
|
||||||
k_is: vec![F::ONE; 6],
|
k_is: vec![F::ONE; 6],
|
||||||
|
num_partial_products: (0, 0),
|
||||||
circuit_digest: Hash::from_partial(vec![]),
|
circuit_digest: Hash::from_partial(vec![]),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -362,7 +367,7 @@ mod tests {
|
|||||||
lpcs[3].merkle_tree.root,
|
lpcs[3].merkle_tree.root,
|
||||||
],
|
],
|
||||||
&mut Challenger::new(),
|
&mut Challenger::new(),
|
||||||
&common_data.config.fri_config,
|
&common_data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
src/proof.rs
12
src/proof.rs
@ -154,6 +154,7 @@ pub struct OpeningSet<F: Field + Extendable<D>, const D: usize> {
|
|||||||
pub wires: Vec<F::Extension>,
|
pub wires: Vec<F::Extension>,
|
||||||
pub plonk_zs: Vec<F::Extension>,
|
pub plonk_zs: Vec<F::Extension>,
|
||||||
pub plonk_zs_right: Vec<F::Extension>,
|
pub plonk_zs_right: Vec<F::Extension>,
|
||||||
|
pub partial_products: Vec<F::Extension>,
|
||||||
pub quotient_polys: Vec<F::Extension>,
|
pub quotient_polys: Vec<F::Extension>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningSet<F, D> {
|
|||||||
g: F::Extension,
|
g: F::Extension,
|
||||||
constants_sigmas_commitment: &ListPolynomialCommitment<F>,
|
constants_sigmas_commitment: &ListPolynomialCommitment<F>,
|
||||||
wires_commitment: &ListPolynomialCommitment<F>,
|
wires_commitment: &ListPolynomialCommitment<F>,
|
||||||
plonk_zs_commitment: &ListPolynomialCommitment<F>,
|
zs_partial_products_commitment: &ListPolynomialCommitment<F>,
|
||||||
quotient_polys_commitment: &ListPolynomialCommitment<F>,
|
quotient_polys_commitment: &ListPolynomialCommitment<F>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -174,12 +175,17 @@ impl<F: Field + Extendable<D>, const D: usize> OpeningSet<F, D> {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
let constants_sigmas_eval = eval_commitment(z, constants_sigmas_commitment);
|
let constants_sigmas_eval = eval_commitment(z, constants_sigmas_commitment);
|
||||||
|
let zs_partial_products_eval = eval_commitment(z, zs_partial_products_commitment);
|
||||||
Self {
|
Self {
|
||||||
constants: constants_sigmas_eval[common_data.constants_range()].to_vec(),
|
constants: constants_sigmas_eval[common_data.constants_range()].to_vec(),
|
||||||
plonk_s_sigmas: constants_sigmas_eval[common_data.sigmas_range()].to_vec(),
|
plonk_s_sigmas: constants_sigmas_eval[common_data.sigmas_range()].to_vec(),
|
||||||
wires: eval_commitment(z, wires_commitment),
|
wires: eval_commitment(z, wires_commitment),
|
||||||
plonk_zs: eval_commitment(z, plonk_zs_commitment),
|
plonk_zs: zs_partial_products_eval[common_data.zs_range()].to_vec(),
|
||||||
plonk_zs_right: eval_commitment(g * z, plonk_zs_commitment),
|
plonk_zs_right: eval_commitment(g * z, zs_partial_products_commitment)
|
||||||
|
[common_data.zs_range()]
|
||||||
|
.to_vec(),
|
||||||
|
partial_products: zs_partial_products_eval[common_data.partial_products_range()]
|
||||||
|
.to_vec(),
|
||||||
quotient_polys: eval_commitment(z, quotient_polys_commitment),
|
quotient_polys: eval_commitment(z, quotient_polys_commitment),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
157
src/prover.rs
157
src/prover.rs
@ -12,6 +12,7 @@ use crate::polynomial::commitment::ListPolynomialCommitment;
|
|||||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||||
use crate::proof::Proof;
|
use crate::proof::Proof;
|
||||||
use crate::timed;
|
use crate::timed;
|
||||||
|
use crate::util::partial_products::partial_products;
|
||||||
use crate::util::{log2_ceil, transpose};
|
use crate::util::{log2_ceil, transpose};
|
||||||
use crate::vars::EvaluationVarsBase;
|
use crate::vars::EvaluationVarsBase;
|
||||||
use crate::witness::{PartialWitness, Witness};
|
use crate::witness::{PartialWitness, Witness};
|
||||||
@ -78,21 +79,34 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
let betas = challenger.get_n_challenges(num_challenges);
|
let betas = challenger.get_n_challenges(num_challenges);
|
||||||
let gammas = challenger.get_n_challenges(num_challenges);
|
let gammas = challenger.get_n_challenges(num_challenges);
|
||||||
|
|
||||||
let plonk_z_vecs = timed!(
|
assert!(
|
||||||
compute_zs(&witness, &betas, &gammas, prover_data, common_data),
|
common_data.quotient_degree_factor + 1 <=common_data.config.num_routed_wires,
|
||||||
"to compute Z's"
|
"When the number of routed wires is smaller that the degree, we should change the logic to avoid computing partial products."
|
||||||
|
);
|
||||||
|
let mut partial_products = timed!(
|
||||||
|
all_wires_permutation_partial_products(&witness, &betas, &gammas, prover_data, common_data),
|
||||||
|
"to compute partial products"
|
||||||
);
|
);
|
||||||
|
|
||||||
let plonk_zs_commitment = timed!(
|
let plonk_z_vecs = timed!(compute_zs(&partial_products, common_data), "to compute Z's");
|
||||||
|
|
||||||
|
// The first polynomial in `partial_products` represent the final product used in the
|
||||||
|
// computation of `Z`. It isn't needed anymore so we discard it.
|
||||||
|
partial_products.iter_mut().for_each(|part| {
|
||||||
|
part.remove(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
let zs_partial_products = [plonk_z_vecs, partial_products.concat()].concat();
|
||||||
|
let zs_partial_products_commitment = timed!(
|
||||||
ListPolynomialCommitment::new(
|
ListPolynomialCommitment::new(
|
||||||
plonk_z_vecs,
|
zs_partial_products,
|
||||||
fri_config.rate_bits,
|
fri_config.rate_bits,
|
||||||
PlonkPolynomials::ZS.blinding
|
PlonkPolynomials::ZS_PARTIAL_PRODUCTS.blinding
|
||||||
),
|
),
|
||||||
"to commit to Z's"
|
"to commit to Z's"
|
||||||
);
|
);
|
||||||
|
|
||||||
challenger.observe_hash(&plonk_zs_commitment.merkle_tree.root);
|
challenger.observe_hash(&zs_partial_products_commitment.merkle_tree.root);
|
||||||
|
|
||||||
let alphas = challenger.get_n_challenges(num_challenges);
|
let alphas = challenger.get_n_challenges(num_challenges);
|
||||||
|
|
||||||
@ -101,7 +115,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
common_data,
|
common_data,
|
||||||
prover_data,
|
prover_data,
|
||||||
&wires_commitment,
|
&wires_commitment,
|
||||||
&plonk_zs_commitment,
|
&zs_partial_products_commitment,
|
||||||
&betas,
|
&betas,
|
||||||
&gammas,
|
&gammas,
|
||||||
&alphas,
|
&alphas,
|
||||||
@ -116,7 +130,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
.flat_map(|mut quotient_poly| {
|
.flat_map(|mut quotient_poly| {
|
||||||
quotient_poly.trim();
|
quotient_poly.trim();
|
||||||
quotient_poly.pad(quotient_degree).expect(
|
quotient_poly.pad(quotient_degree).expect(
|
||||||
"The quotient polynomial doesn't have the right degree.\
|
"The quotient polynomial doesn't have the right degree. \
|
||||||
This may be because the `Z`s polynomials are still too high degree.",
|
This may be because the `Z`s polynomials are still too high degree.",
|
||||||
);
|
);
|
||||||
// Split t into degree-n chunks.
|
// Split t into degree-n chunks.
|
||||||
@ -144,7 +158,7 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
&[
|
&[
|
||||||
&prover_data.constants_sigmas_commitment,
|
&prover_data.constants_sigmas_commitment,
|
||||||
&wires_commitment,
|
&wires_commitment,
|
||||||
&plonk_zs_commitment,
|
&zs_partial_products_commitment,
|
||||||
"ient_polys_commitment,
|
"ient_polys_commitment,
|
||||||
],
|
],
|
||||||
zeta,
|
zeta,
|
||||||
@ -161,50 +175,103 @@ pub(crate) fn prove<F: Extendable<D>, const D: usize>(
|
|||||||
|
|
||||||
Proof {
|
Proof {
|
||||||
wires_root: wires_commitment.merkle_tree.root,
|
wires_root: wires_commitment.merkle_tree.root,
|
||||||
plonk_zs_root: plonk_zs_commitment.merkle_tree.root,
|
plonk_zs_root: zs_partial_products_commitment.merkle_tree.root,
|
||||||
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
|
quotient_polys_root: quotient_polys_commitment.merkle_tree.root,
|
||||||
openings,
|
openings,
|
||||||
opening_proof,
|
opening_proof,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_zs<F: Extendable<D>, const D: usize>(
|
/// Compute the partial products used in the `Z` polynomials.
|
||||||
|
fn all_wires_permutation_partial_products<F: Extendable<D>, const D: usize>(
|
||||||
witness: &Witness<F>,
|
witness: &Witness<F>,
|
||||||
betas: &[F],
|
betas: &[F],
|
||||||
gammas: &[F],
|
gammas: &[F],
|
||||||
prover_data: &ProverOnlyCircuitData<F, D>,
|
prover_data: &ProverOnlyCircuitData<F, D>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Vec<PolynomialValues<F>> {
|
) -> Vec<Vec<PolynomialValues<F>>> {
|
||||||
(0..common_data.config.num_challenges)
|
(0..common_data.config.num_challenges)
|
||||||
.map(|i| compute_z(witness, betas[i], gammas[i], prover_data, common_data))
|
.map(|i| {
|
||||||
|
wires_permutation_partial_products(
|
||||||
|
witness,
|
||||||
|
betas[i],
|
||||||
|
gammas[i],
|
||||||
|
prover_data,
|
||||||
|
common_data,
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_z<F: Extendable<D>, const D: usize>(
|
/// Compute the partial products used in the `Z` polynomial.
|
||||||
|
/// Returns the polynomials interpolating `partial_products(f / g)`
|
||||||
|
/// where `f, g` are the products in the definition of `Z`: `Z(g^i) = f / g`.
|
||||||
|
fn wires_permutation_partial_products<F: Extendable<D>, const D: usize>(
|
||||||
witness: &Witness<F>,
|
witness: &Witness<F>,
|
||||||
beta: F,
|
beta: F,
|
||||||
gamma: F,
|
gamma: F,
|
||||||
prover_data: &ProverOnlyCircuitData<F, D>,
|
prover_data: &ProverOnlyCircuitData<F, D>,
|
||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> PolynomialValues<F> {
|
) -> Vec<PolynomialValues<F>> {
|
||||||
|
let degree = common_data.quotient_degree_factor;
|
||||||
let subgroup = &prover_data.subgroup;
|
let subgroup = &prover_data.subgroup;
|
||||||
let mut plonk_z_points = vec![F::ONE];
|
|
||||||
let k_is = &common_data.k_is;
|
let k_is = &common_data.k_is;
|
||||||
|
let values = subgroup
|
||||||
|
.par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, &x)| {
|
||||||
|
let s_sigmas = &prover_data.sigmas[i];
|
||||||
|
let quotient_values = (0..common_data.config.num_routed_wires)
|
||||||
|
.map(|j| {
|
||||||
|
let wire_value = witness.get_wire(i, j);
|
||||||
|
let k_i = k_is[j];
|
||||||
|
let s_id = k_i * x;
|
||||||
|
let s_sigma = s_sigmas[j];
|
||||||
|
let numerator = wire_value + beta * s_id + gamma;
|
||||||
|
let denominator = wire_value + beta * s_sigma + gamma;
|
||||||
|
numerator / denominator
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let quotient_partials = partial_products("ient_values, degree);
|
||||||
|
|
||||||
|
// This is the final product for the quotient.
|
||||||
|
let quotient = quotient_partials
|
||||||
|
[common_data.num_partial_products.0 - common_data.num_partial_products.1..]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.product();
|
||||||
|
|
||||||
|
// We add the quotient at the beginning of the vector to reuse them later in the computation of `Z`.
|
||||||
|
[vec![quotient], quotient_partials].concat()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
transpose(&values)
|
||||||
|
.into_par_iter()
|
||||||
|
.map(PolynomialValues::new)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_zs<F: Extendable<D>, const D: usize>(
|
||||||
|
partial_products: &[Vec<PolynomialValues<F>>],
|
||||||
|
common_data: &CommonCircuitData<F, D>,
|
||||||
|
) -> Vec<PolynomialValues<F>> {
|
||||||
|
(0..common_data.config.num_challenges)
|
||||||
|
.map(|i| compute_z(&partial_products[i], common_data))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the `Z` polynomial by reusing the computations done in `wires_permutation_partial_products`.
|
||||||
|
fn compute_z<F: Extendable<D>, const D: usize>(
|
||||||
|
partial_products: &[PolynomialValues<F>],
|
||||||
|
common_data: &CommonCircuitData<F, D>,
|
||||||
|
) -> PolynomialValues<F> {
|
||||||
|
let mut plonk_z_points = vec![F::ONE];
|
||||||
for i in 1..common_data.degree() {
|
for i in 1..common_data.degree() {
|
||||||
let x = subgroup[i - 1];
|
let quotient = partial_products[0].values[i - 1];
|
||||||
let mut numerator = F::ONE;
|
|
||||||
let mut denominator = F::ONE;
|
|
||||||
let s_sigmas = &prover_data.sigmas[i - 1];
|
|
||||||
for j in 0..common_data.config.num_routed_wires {
|
|
||||||
let wire_value = witness.get_wire(i - 1, j);
|
|
||||||
let k_i = k_is[j];
|
|
||||||
let s_id = k_i * x;
|
|
||||||
let s_sigma = s_sigmas[j];
|
|
||||||
numerator *= wire_value + beta * s_id + gamma;
|
|
||||||
denominator *= wire_value + beta * s_sigma + gamma;
|
|
||||||
}
|
|
||||||
let last = *plonk_z_points.last().unwrap();
|
let last = *plonk_z_points.last().unwrap();
|
||||||
plonk_z_points.push(last * numerator / denominator);
|
plonk_z_points.push(last * quotient);
|
||||||
}
|
}
|
||||||
plonk_z_points.into()
|
plonk_z_points.into()
|
||||||
}
|
}
|
||||||
@ -213,28 +280,27 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
|||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
prover_data: &'a ProverOnlyCircuitData<F, D>,
|
prover_data: &'a ProverOnlyCircuitData<F, D>,
|
||||||
wires_commitment: &'a ListPolynomialCommitment<F>,
|
wires_commitment: &'a ListPolynomialCommitment<F>,
|
||||||
plonk_zs_commitment: &'a ListPolynomialCommitment<F>,
|
zs_partial_products_commitment: &'a ListPolynomialCommitment<F>,
|
||||||
betas: &[F],
|
betas: &[F],
|
||||||
gammas: &[F],
|
gammas: &[F],
|
||||||
alphas: &[F],
|
alphas: &[F],
|
||||||
) -> Vec<PolynomialCoeffs<F>> {
|
) -> Vec<PolynomialCoeffs<F>> {
|
||||||
let num_challenges = common_data.config.num_challenges;
|
let num_challenges = common_data.config.num_challenges;
|
||||||
let max_filtered_constraint_degree_bits = log2_ceil(common_data.max_filtered_constraint_degree);
|
let max_degree_bits = log2_ceil(common_data.quotient_degree_factor + 1);
|
||||||
assert!(
|
assert!(
|
||||||
max_filtered_constraint_degree_bits <= common_data.config.rate_bits,
|
max_degree_bits <= common_data.config.rate_bits,
|
||||||
"Having constraints of degree higher than the rate is not supported yet. \
|
"Having constraints of degree higher than the rate is not supported yet. \
|
||||||
If we need this in the future, we can precompute the larger LDE before computing the `ListPolynomialCommitment`s."
|
If we need this in the future, we can precompute the larger LDE before computing the `ListPolynomialCommitment`s."
|
||||||
);
|
);
|
||||||
|
|
||||||
// We reuse the LDE computed in `ListPolynomialCommitment` and extract every `step` points to get
|
// We reuse the LDE computed in `ListPolynomialCommitment` and extract every `step` points to get
|
||||||
// an LDE matching `max_filtered_constraint_degree`.
|
// an LDE matching `max_filtered_constraint_degree`.
|
||||||
let step = 1 << (common_data.config.rate_bits - max_filtered_constraint_degree_bits);
|
let step = 1 << (common_data.config.rate_bits - max_degree_bits);
|
||||||
// When opening the `Z`s polys at the "next" point in Plonk, need to look at the point `next_step`
|
// When opening the `Z`s polys at the "next" point in Plonk, need to look at the point `next_step`
|
||||||
// steps away since we work on an LDE of degree `max_filtered_constraint_degree`.
|
// steps away since we work on an LDE of degree `max_filtered_constraint_degree`.
|
||||||
let next_step = 1 << max_filtered_constraint_degree_bits;
|
let next_step = 1 << max_degree_bits;
|
||||||
|
|
||||||
let points =
|
let points = F::two_adic_subgroup(common_data.degree_bits + max_degree_bits);
|
||||||
F::two_adic_subgroup(common_data.degree_bits + max_filtered_constraint_degree_bits);
|
|
||||||
let lde_size = points.len();
|
let lde_size = points.len();
|
||||||
|
|
||||||
// Retrieve the LDE values at index `i`.
|
// Retrieve the LDE values at index `i`.
|
||||||
@ -242,8 +308,7 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
|||||||
comm.get_lde_values(i * step)
|
comm.get_lde_values(i * step)
|
||||||
};
|
};
|
||||||
|
|
||||||
let z_h_on_coset =
|
let z_h_on_coset = ZeroPolyOnCoset::new(common_data.degree_bits, max_degree_bits);
|
||||||
ZeroPolyOnCoset::new(common_data.degree_bits, max_filtered_constraint_degree_bits);
|
|
||||||
|
|
||||||
let quotient_values: Vec<Vec<F>> = points
|
let quotient_values: Vec<Vec<F>> = points
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
@ -255,11 +320,14 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
|||||||
let local_constants = &local_constants_sigmas[common_data.constants_range()];
|
let local_constants = &local_constants_sigmas[common_data.constants_range()];
|
||||||
let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()];
|
let s_sigmas = &local_constants_sigmas[common_data.sigmas_range()];
|
||||||
let local_wires = get_at_index(wires_commitment, i);
|
let local_wires = get_at_index(wires_commitment, i);
|
||||||
let local_plonk_zs = get_at_index(plonk_zs_commitment, i);
|
let local_zs_partial_products = get_at_index(zs_partial_products_commitment, i);
|
||||||
let next_plonk_zs = get_at_index(plonk_zs_commitment, i_next);
|
let local_zs = &local_zs_partial_products[common_data.zs_range()];
|
||||||
|
let next_zs =
|
||||||
|
&get_at_index(zs_partial_products_commitment, i_next)[common_data.zs_range()];
|
||||||
|
let partial_products = &local_zs_partial_products[common_data.partial_products_range()];
|
||||||
|
|
||||||
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
|
debug_assert_eq!(local_wires.len(), common_data.config.num_wires);
|
||||||
debug_assert_eq!(local_plonk_zs.len(), num_challenges);
|
debug_assert_eq!(local_zs.len(), num_challenges);
|
||||||
|
|
||||||
let vars = EvaluationVarsBase {
|
let vars = EvaluationVarsBase {
|
||||||
local_constants,
|
local_constants,
|
||||||
@ -270,8 +338,9 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
|||||||
i,
|
i,
|
||||||
shifted_x,
|
shifted_x,
|
||||||
vars,
|
vars,
|
||||||
local_plonk_zs,
|
local_zs,
|
||||||
next_plonk_zs,
|
next_zs,
|
||||||
|
partial_products,
|
||||||
s_sigmas,
|
s_sigmas,
|
||||||
betas,
|
betas,
|
||||||
gammas,
|
gammas,
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
pub mod partial_products;
|
||||||
pub mod scaling;
|
pub mod scaling;
|
||||||
pub(crate) mod timing;
|
pub(crate) mod timing;
|
||||||
|
|
||||||
|
|||||||
95
src/util/partial_products.rs
Normal file
95
src/util/partial_products.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
use std::iter::Product;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
use crate::util::ceil_div_usize;
|
||||||
|
|
||||||
|
/// Compute partial products of the original vector `v` such that all products consist of `max_degree`
|
||||||
|
/// or less elements. This is done until we've computed the product `P` of all elements in the vector.
|
||||||
|
pub fn partial_products<T: Product + Copy>(v: &[T], max_degree: usize) -> Vec<T> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let mut remainder = v.to_vec();
|
||||||
|
while remainder.len() > max_degree {
|
||||||
|
let new_partials = remainder
|
||||||
|
.chunks(max_degree)
|
||||||
|
// TODO: can filter out chunks of length 1.
|
||||||
|
.map(|chunk| chunk.iter().copied().product())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
res.extend_from_slice(&new_partials);
|
||||||
|
remainder = new_partials;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a tuple `(a,b)`, where `a` is the length of the output of `partial_products()` on a
|
||||||
|
/// vector of length `n`, and `b` is the number of elements needed to compute the final product.
|
||||||
|
pub fn num_partial_products(n: usize, max_degree: usize) -> (usize, usize) {
|
||||||
|
debug_assert!(max_degree > 1);
|
||||||
|
let mut res = 0;
|
||||||
|
let mut remainder = n;
|
||||||
|
while remainder > max_degree {
|
||||||
|
let new_partials_len = ceil_div_usize(remainder, max_degree);
|
||||||
|
res += new_partials_len;
|
||||||
|
remainder = new_partials_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
(res, remainder)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks that the partial products of `v` are coherent with those in `partials` by only computing
|
||||||
|
/// products of size `max_degree` or less.
|
||||||
|
pub fn check_partial_products<T: Product + Copy + Sub<Output = T>>(
|
||||||
|
v: &[T],
|
||||||
|
partials: &[T],
|
||||||
|
max_degree: usize,
|
||||||
|
) -> Vec<T> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let mut remainder = v.to_vec();
|
||||||
|
let mut partials = partials.to_vec();
|
||||||
|
while remainder.len() > max_degree {
|
||||||
|
let products = remainder
|
||||||
|
.chunks(max_degree)
|
||||||
|
.map(|chunk| chunk.iter().copied().product())
|
||||||
|
.collect::<Vec<T>>();
|
||||||
|
res.extend(products.iter().zip(&partials).map(|(&a, &b)| a - b));
|
||||||
|
remainder = partials.drain(..products.len()).collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use num::Zero;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_partial_products() {
|
||||||
|
let v = vec![1, 2, 3, 4, 5, 6];
|
||||||
|
let p = partial_products(&v, 2);
|
||||||
|
assert_eq!(p, vec![2, 12, 30, 24, 30]);
|
||||||
|
let nums = num_partial_products(v.len(), 2);
|
||||||
|
assert_eq!(p.len(), nums.0);
|
||||||
|
assert!(check_partial_products(&v, &p, 2)
|
||||||
|
.iter()
|
||||||
|
.all(|x| x.is_zero()));
|
||||||
|
assert_eq!(
|
||||||
|
v.into_iter().product::<i32>(),
|
||||||
|
p[p.len() - nums.1..].iter().copied().product(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let v = vec![1, 2, 3, 4, 5, 6];
|
||||||
|
let p = partial_products(&v, 3);
|
||||||
|
assert_eq!(p, vec![6, 120]);
|
||||||
|
let nums = num_partial_products(v.len(), 3);
|
||||||
|
assert_eq!(p.len(), nums.0);
|
||||||
|
assert!(check_partial_products(&v, &p, 3)
|
||||||
|
.iter()
|
||||||
|
.all(|x| x.is_zero()));
|
||||||
|
assert_eq!(
|
||||||
|
v.into_iter().product::<i32>(),
|
||||||
|
p[p.len() - nums.1..].iter().copied().product(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -174,6 +174,7 @@ mod tests {
|
|||||||
use crate::circuit_data::CircuitConfig;
|
use crate::circuit_data::CircuitConfig;
|
||||||
use crate::field::crandall_field::CrandallField;
|
use crate::field::crandall_field::CrandallField;
|
||||||
use crate::field::extension_field::quartic::QuarticCrandallField;
|
use crate::field::extension_field::quartic::QuarticCrandallField;
|
||||||
|
use crate::verifier::verify;
|
||||||
use crate::witness::PartialWitness;
|
use crate::witness::PartialWitness;
|
||||||
|
|
||||||
fn test_reduce_gadget(n: usize) {
|
fn test_reduce_gadget(n: usize) {
|
||||||
@ -205,6 +206,8 @@ mod tests {
|
|||||||
|
|
||||||
let data = builder.build();
|
let data = builder.build();
|
||||||
let proof = data.prove(PartialWitness::new());
|
let proof = data.prove(PartialWitness::new());
|
||||||
|
|
||||||
|
verify(proof, &data.verifier_only, &data.common).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -2,8 +2,9 @@ use anyhow::{ensure, Result};
|
|||||||
|
|
||||||
use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
use crate::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
|
||||||
use crate::field::extension_field::Extendable;
|
use crate::field::extension_field::Extendable;
|
||||||
|
use crate::field::field::Field;
|
||||||
use crate::plonk_challenger::Challenger;
|
use crate::plonk_challenger::Challenger;
|
||||||
use crate::plonk_common::{eval_vanishing_poly, eval_zero_poly};
|
use crate::plonk_common::{eval_vanishing_poly, eval_zero_poly, reduce_with_powers};
|
||||||
use crate::proof::Proof;
|
use crate::proof::Proof;
|
||||||
use crate::vars::EvaluationVars;
|
use crate::vars::EvaluationVars;
|
||||||
|
|
||||||
@ -13,7 +14,6 @@ pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
|||||||
common_data: &CommonCircuitData<F, D>,
|
common_data: &CommonCircuitData<F, D>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = &common_data.config;
|
let config = &common_data.config;
|
||||||
let fri_config = &config.fri_config;
|
|
||||||
let num_challenges = config.num_challenges;
|
let num_challenges = config.num_challenges;
|
||||||
|
|
||||||
let mut challenger = Challenger::new();
|
let mut challenger = Challenger::new();
|
||||||
@ -37,17 +37,19 @@ pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
|||||||
local_constants,
|
local_constants,
|
||||||
local_wires,
|
local_wires,
|
||||||
};
|
};
|
||||||
let local_plonk_zs = &proof.openings.plonk_zs;
|
let local_zs = &proof.openings.plonk_zs;
|
||||||
let next_plonk_zs = &proof.openings.plonk_zs_right;
|
let next_zs = &proof.openings.plonk_zs_right;
|
||||||
let s_sigmas = &proof.openings.plonk_s_sigmas;
|
let s_sigmas = &proof.openings.plonk_s_sigmas;
|
||||||
|
let partial_products = &proof.openings.partial_products;
|
||||||
|
|
||||||
// Evaluate the vanishing polynomial at our challenge point, zeta.
|
// Evaluate the vanishing polynomial at our challenge point, zeta.
|
||||||
let vanishing_polys_zeta = eval_vanishing_poly(
|
let vanishing_polys_zeta = eval_vanishing_poly(
|
||||||
common_data,
|
common_data,
|
||||||
zeta,
|
zeta,
|
||||||
vars,
|
vars,
|
||||||
local_plonk_zs,
|
local_zs,
|
||||||
next_plonk_zs,
|
next_zs,
|
||||||
|
partial_products,
|
||||||
s_sigmas,
|
s_sigmas,
|
||||||
&betas,
|
&betas,
|
||||||
&gammas,
|
&gammas,
|
||||||
@ -56,9 +58,18 @@ pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
|||||||
|
|
||||||
// Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta.
|
// Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta.
|
||||||
let quotient_polys_zeta = &proof.openings.quotient_polys;
|
let quotient_polys_zeta = &proof.openings.quotient_polys;
|
||||||
let z_h_zeta = eval_zero_poly(common_data.degree(), zeta);
|
let zeta_pow_deg = zeta.exp_power_of_2(common_data.degree_bits);
|
||||||
for i in 0..num_challenges {
|
let z_h_zeta = zeta_pow_deg - F::Extension::ONE;
|
||||||
ensure!(vanishing_polys_zeta[i] == z_h_zeta * quotient_polys_zeta[i]);
|
// `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations.
|
||||||
|
// Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)`
|
||||||
|
// where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`.
|
||||||
|
// So to reconstruct `t(zeta)` we can compute `reduce_with_powers(chunk, zeta^n)` for each
|
||||||
|
// `quotient_degree_factor`-sized chunk of the original evaluations.
|
||||||
|
for (i, chunk) in quotient_polys_zeta
|
||||||
|
.chunks(common_data.quotient_degree_factor)
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
ensure!(vanishing_polys_zeta[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg));
|
||||||
}
|
}
|
||||||
|
|
||||||
let evaluations = proof.openings.clone();
|
let evaluations = proof.openings.clone();
|
||||||
@ -75,7 +86,7 @@ pub(crate) fn verify<F: Extendable<D>, const D: usize>(
|
|||||||
&evaluations,
|
&evaluations,
|
||||||
merkle_roots,
|
merkle_roots,
|
||||||
&mut challenger,
|
&mut challenger,
|
||||||
fri_config,
|
common_data,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user