This commit is contained in:
wborgeaud 2022-03-25 07:52:39 +01:00
parent d6b99df876
commit 847565a8c3
5 changed files with 114 additions and 95 deletions

View File

@ -7,6 +7,7 @@ use plonky2_field::batch_util::batch_multiply_inplace;
use plonky2_field::extension_field::{Extendable, FieldExtension};
use plonky2_field::field_types::Field;
use crate::gates::selectors::UNUSED_SELECTOR;
use crate::gates::util::StridedConstraintConsumer;
use crate::hash::hash_types::RichField;
use crate::iop::ext_target::ExtensionTarget;
@ -84,12 +85,12 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
mut vars: EvaluationVars<F, D>,
gate_index: usize,
selector_index: usize,
combination_range: (usize, usize),
group_range: (usize, usize),
num_selectors: usize,
) -> Vec<F::Extension> {
let filter = compute_filter(
gate_index,
combination_range,
group_range,
vars.local_constants[selector_index],
);
vars.remove_prefix(num_selectors);
@ -106,7 +107,7 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
mut vars_batch: EvaluationVarsBaseBatch<F>,
gate_index: usize,
selector_index: usize,
combination_range: (usize, usize),
group_range: (usize, usize),
num_selectors: usize,
) -> Vec<F> {
let filters: Vec<_> = vars_batch
@ -114,7 +115,7 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
.map(|vars| {
compute_filter(
gate_index,
combination_range,
group_range,
vars.local_constants[selector_index],
)
})
@ -134,14 +135,14 @@ pub trait Gate<F: RichField + Extendable<D>, const D: usize>: 'static + Send + S
mut vars: EvaluationTargets<D>,
gate_index: usize,
selector_index: usize,
combination_range: (usize, usize),
combined_gate_constraints: &mut [ExtensionTarget<D>],
group_range: (usize, usize),
num_selectors: usize,
combined_gate_constraints: &mut [ExtensionTarget<D>],
) {
let filter = compute_filter_recursively(
builder,
gate_index,
combination_range,
group_range,
vars.local_constants[selector_index],
);
vars.remove_prefix(num_selectors);
@ -229,34 +230,30 @@ pub struct PrefixedGate<F: RichField + Extendable<D>, const D: usize> {
pub prefix: Vec<bool>,
}
/// A gate's filter is computed as `prod b_i*c_i + (1-b_i)*(1-c_i)`, with `(b_i)` the prefix and
/// `(c_i)` the local constants, which is one if the prefix of `constants` matches `prefix`.
fn compute_filter<K: Field>(
gate_index: usize,
combination_range: (usize, usize),
constant: K,
) -> K {
(combination_range.0..combination_range.1)
/// A gate's filter designed so that it is non-zero if `s = gate_index`.
fn compute_filter<K: Field>(gate_index: usize, group_range: (usize, usize), s: K) -> K {
debug_assert!((group_range.0 <= gate_index) && (gate_index < group_range.1));
(group_range.0..group_range.1)
.filter(|&i| i != gate_index)
.chain(Some(u32::MAX as usize))
.map(|i| K::from_canonical_usize(i) - constant)
.chain(Some(UNUSED_SELECTOR))
.map(|i| K::from_canonical_usize(i) - s)
.product()
}
fn compute_filter_recursively<F: RichField + Extendable<D>, const D: usize>(
builder: &mut CircuitBuilder<F, D>,
gate_index: usize,
combination_range: (usize, usize),
constant: ExtensionTarget<D>,
group_range: (usize, usize),
s: ExtensionTarget<D>,
) -> ExtensionTarget<D> {
let v = (combination_range.0..combination_range.1)
debug_assert!((group_range.0 <= gate_index) && (gate_index < group_range.1));
let v = (group_range.0..group_range.1)
.filter(|&i| i != gate_index)
.chain(Some(u32::MAX as usize))
.map(|i| builder.constant_extension(F::Extension::from_canonical_usize(i)))
.collect::<Vec<_>>();
let v = v
.into_iter()
.map(|x| builder.sub_extension(x, constant))
.chain(Some(UNUSED_SELECTOR))
.map(|i| {
let c = builder.constant_extension(F::Extension::from_canonical_usize(i));
builder.sub_extension(c, s)
})
.collect::<Vec<_>>();
builder.mul_many_extension(&v)
}

View File

@ -4,74 +4,73 @@ use plonky2_field::polynomial::PolynomialValues;
use crate::gates::gate::{GateInstance, GateRef};
use crate::hash::hash_types::RichField;
pub(crate) fn compute_selectors<F: RichField + Extendable<D>, const D: usize>(
/// Placeholder value to indicate that a gate doesn't use a selector polynomial.
pub(crate) const UNUSED_SELECTOR: usize = u32::MAX as usize;
#[derive(Debug, Clone)]
pub(crate) struct SelectorsInfo {
pub(crate) selector_indices: Vec<usize>,
pub(crate) groups: Vec<(usize, usize)>,
pub(crate) num_selectors: usize,
}
/// Returns the selector polynomials and related information.
///
/// Selector polynomials are computed as follows:
/// Partition the gates into (the smallest amount of) groups `{ G_i }`, such that for each group `G`
/// `|G| + max_{g in G} g.degree() <= max_degree`. These groups are constructed greedily from
/// the list of gates sorted by degree.
pub(crate) fn selector_polynomials<F: RichField + Extendable<D>, const D: usize>(
gates: Vec<GateRef<F, D>>,
instances: &[GateInstance<F, D>],
max_degree: usize,
) -> (
Vec<PolynomialValues<F>>,
Vec<usize>,
Vec<(usize, usize)>,
usize,
) {
) -> (Vec<PolynomialValues<F>>, SelectorsInfo) {
let n = instances.len();
let mut combinations = Vec::new();
// Greedily construct the groups.
let mut groups = Vec::new();
let mut pos = 0;
while pos < gates.len() {
let mut i = 0;
while (pos + i < gates.len()) && (i + gates[pos + i].0.degree() < max_degree) {
i += 1;
}
combinations.push((pos, pos + i));
groups.push((pos, pos + i));
pos += i;
}
let bad = F::from_canonical_usize(u32::MAX as usize);
let num_constants_polynomials = gates.iter().map(|g| g.0.num_constants()).max().unwrap();
let mut polynomials =
vec![PolynomialValues::zero(n); combinations.len() + num_constants_polynomials];
let index = |id| gates.iter().position(|g| g.0.id() == id).unwrap();
let combination = |i| {
combinations
.iter()
.position(|&(a, b)| a <= i && i < b)
.unwrap()
};
let group = |i| groups.iter().position(|&(a, b)| a <= i && i < b).unwrap();
// `selector_indices[i] = j` iff the `i`-th gate uses the `j`-th selector polynomial.
let selector_indices = gates
.iter()
.map(|g| combination(index(g.0.id())))
.map(|g| group(index(g.0.id())))
.collect::<Vec<_>>();
let combination_ranges = selector_indices
.iter()
.map(|&i| (combinations[i].0, combinations[i].1))
.collect();
// Placeholder value to indicate that a gate doesn't use a selector polynomial.
let unused = F::from_canonical_usize(UNUSED_SELECTOR);
let mut polynomials = vec![PolynomialValues::zero(n); groups.len()];
for (j, g) in instances.iter().enumerate() {
let GateInstance {
gate_ref,
constants,
} = g;
let GateInstance { gate_ref, .. } = g;
let i = index(gate_ref.0.id());
let comb = combination(i);
polynomials[comb].values[j] = F::from_canonical_usize(i);
for combis in (0..combinations.len()).filter(|&combis| combis != comb) {
polynomials[combis].values[j] = bad;
}
for k in 0..constants.len() {
polynomials[combinations.len() + k].values[j] = constants[k];
let gr = group(i);
for g in 0..groups.len() {
polynomials[g].values[j] = if g == gr {
F::from_canonical_usize(i)
} else {
unused
};
}
}
(
polynomials,
selector_indices,
combination_ranges,
combinations.len(),
SelectorsInfo {
selector_indices,
num_selectors: groups.len(),
groups,
},
)
}

View File

@ -22,7 +22,7 @@ use crate::gates::constant::ConstantGate;
use crate::gates::gate::{CurrentSlot, Gate, GateInstance, GateRef};
use crate::gates::noop::NoopGate;
use crate::gates::public_input::PublicInputGate;
use crate::gates::selectors::compute_selectors;
use crate::gates::selectors::selector_polynomials;
use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField};
use crate::hash::merkle_proofs::MerkleProofTarget;
use crate::iop::ext_target::ExtensionTarget;
@ -44,7 +44,7 @@ use crate::util::context_tree::ContextTree;
use crate::util::marking::{Markable, MarkedTargets};
use crate::util::partial_products::num_partial_products;
use crate::util::timing::TimingTree;
use crate::util::transpose_poly_values;
use crate::util::{transpose, transpose_poly_values};
pub struct CircuitBuilder<F: RichField + Extendable<D>, const D: usize> {
pub config: CircuitConfig,
@ -551,6 +551,29 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}
}
fn constant_polys(&self) -> Vec<PolynomialValues<F>> {
let max_constants = self
.gates
.iter()
.map(|g| g.0.num_constants())
.max()
.unwrap();
transpose(
&self
.gate_instances
.iter()
.map(|g| {
let mut consts = g.constants.clone();
consts.resize(max_constants, F::ZERO);
consts
})
.collect::<Vec<_>>(),
)
.into_iter()
.map(PolynomialValues::new)
.collect()
}
fn sigma_vecs(&self, k_is: &[F], subgroup: &[F]) -> (Vec<PolynomialValues<F>>, Forest) {
let degree = self.gate_instances.len();
let degree_log = log2_strict(degree);
@ -641,17 +664,16 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
"FRI total reduction arity is too large.",
);
let mut gates = self.gates.iter().cloned().collect::<Vec<_>>();
gates.sort_unstable_by_key(|g| g.0.degree());
let (constant_vecs, selector_indices, combination_ranges, num_selectors) =
compute_selectors(
gates.clone(),
&self.gate_instances,
self.config.max_quotient_degree_factor + 1,
);
let num_constants = constant_vecs.len();
let quotient_degree_factor = self.config.max_quotient_degree_factor;
debug!("Quotient degree factor set to: {}.", quotient_degree_factor);
let mut gates = self.gates.iter().cloned().collect::<Vec<_>>();
gates.sort_unstable_by_key(|g| (g.0.degree(), g.0.id()));
let (mut constant_vecs, selectors_info) = selector_polynomials(
gates.clone(),
&self.gate_instances,
quotient_degree_factor + 1,
);
constant_vecs.extend(self.constant_polys());
let num_constants = constant_vecs.len();
let subgroup = F::two_adic_subgroup(degree_bits);
@ -754,9 +776,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fri_params,
degree_bits,
gates,
selector_indices,
combination_ranges,
num_selectors,
selectors_info,
quotient_degree_factor,
num_gate_constraints,
num_constants,

View File

@ -13,6 +13,7 @@ use crate::fri::structure::{
};
use crate::fri::{FriConfig, FriParams};
use crate::gates::gate::GateRef;
use crate::gates::selectors::SelectorsInfo;
use crate::hash::hash_types::{MerkleCapTarget, RichField};
use crate::hash::merkle_tree::MerkleCap;
use crate::iop::ext_target::ExtensionTarget;
@ -248,9 +249,8 @@ pub struct CommonCircuitData<
/// The types of gates used in this circuit, along with their prefixes.
pub(crate) gates: Vec<GateRef<F, D>>,
pub(crate) selector_indices: Vec<usize>,
pub(crate) combination_ranges: Vec<(usize, usize)>,
pub(crate) num_selectors: usize,
/// Information on the circuit's selector polynomials.
pub(crate) selectors_info: SelectorsInfo,
/// The degree of the PLONK quotient polynomial.
pub(crate) quotient_degree_factor: usize,

View File

@ -215,12 +215,13 @@ pub fn evaluate_gate_constraints<
) -> Vec<F::Extension> {
let mut constraints = vec![F::Extension::ZERO; common_data.num_gate_constraints];
for (i, gate) in common_data.gates.iter().enumerate() {
let selector_index = common_data.selectors_info.selector_indices[i];
let gate_constraints = gate.0.eval_filtered(
vars,
i,
common_data.selector_indices[i],
common_data.combination_ranges[i],
common_data.num_selectors,
selector_index,
common_data.selectors_info.groups[selector_index],
common_data.selectors_info.num_selectors,
);
for (i, c) in gate_constraints.into_iter().enumerate() {
debug_assert!(
@ -248,12 +249,13 @@ pub fn evaluate_gate_constraints_base_batch<
) -> Vec<F> {
let mut constraints_batch = vec![F::ZERO; common_data.num_gate_constraints * vars_batch.len()];
for (i, gate) in common_data.gates.iter().enumerate() {
let selector_index = common_data.selectors_info.selector_indices[i];
let gate_constraints_batch = gate.0.eval_filtered_base_batch(
vars_batch,
i,
common_data.selector_indices[i],
common_data.combination_ranges[i],
common_data.num_selectors,
selector_index,
common_data.selectors_info.groups[selector_index],
common_data.selectors_info.num_selectors,
);
debug_assert!(
gate_constraints_batch.len() <= constraints_batch.len(),
@ -279,6 +281,7 @@ pub fn evaluate_gate_constraints_recursively<
) -> Vec<ExtensionTarget<D>> {
let mut all_gate_constraints = vec![builder.zero_extension(); common_data.num_gate_constraints];
for (i, gate) in common_data.gates.iter().enumerate() {
let selector_index = common_data.selectors_info.selector_indices[i];
with_context!(
builder,
&format!("evaluate {} constraints", gate.0.id()),
@ -286,10 +289,10 @@ pub fn evaluate_gate_constraints_recursively<
builder,
vars,
i,
common_data.selector_indices[i],
common_data.combination_ranges[i],
selector_index,
common_data.selectors_info.groups[selector_index],
common_data.selectors_info.num_selectors,
&mut all_gate_constraints,
common_data.num_selectors
)
);
}