mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 00:03:10 +00:00
Choose between high- and low-degree interpolation gate depending on the arity
This commit is contained in:
parent
8522026c36
commit
6aaea002ed
@ -3,8 +3,10 @@ use crate::field::extension_field::Extendable;
|
||||
use crate::field::field_types::{Field, RichField};
|
||||
use crate::fri::proof::{FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget};
|
||||
use crate::fri::FriConfig;
|
||||
use crate::gadgets::interpolation::InterpolationGate;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::gates::interpolation::InterpolationGate;
|
||||
use crate::gates::interpolation::HighDegreeInterpolationGate;
|
||||
use crate::gates::low_degree_interpolation::LowDegreeInterpolationGate;
|
||||
use crate::gates::random_access::RandomAccessGate;
|
||||
use crate::hash::hash_types::MerkleCapTarget;
|
||||
use crate::iop::challenger::RecursiveChallenger;
|
||||
@ -27,6 +29,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
arity_bits: usize,
|
||||
evals: &[ExtensionTarget<D>],
|
||||
beta: ExtensionTarget<D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> ExtensionTarget<D> {
|
||||
let arity = 1 << arity_bits;
|
||||
debug_assert_eq!(evals.len(), arity);
|
||||
@ -43,7 +46,21 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
let coset_start = self.mul(start, x);
|
||||
|
||||
// The answer is gotten by interpolating {(x*g^i, P(x*g^i))} and evaluating at beta.
|
||||
self.interpolate_coset(arity_bits, coset_start, &evals, beta)
|
||||
if 1 << arity_bits > common_data.quotient_degree_factor {
|
||||
self.interpolate_coset::<LowDegreeInterpolationGate<F, D>>(
|
||||
arity_bits,
|
||||
coset_start,
|
||||
&evals,
|
||||
beta,
|
||||
)
|
||||
} else {
|
||||
self.interpolate_coset::<HighDegreeInterpolationGate<F, D>>(
|
||||
arity_bits,
|
||||
coset_start,
|
||||
&evals,
|
||||
beta,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure we have enough wires and routed wires to do the FRI checks efficiently. This check
|
||||
@ -54,7 +71,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
&self.config,
|
||||
max_fri_arity_bits.max(self.config.cap_height),
|
||||
);
|
||||
let interpolation_gate = InterpolationGate::<F, D>::new(max_fri_arity_bits);
|
||||
let interpolation_gate = HighDegreeInterpolationGate::<F, D>::new(max_fri_arity_bits);
|
||||
|
||||
let min_wires = random_access
|
||||
.num_wires()
|
||||
@ -379,6 +396,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
arity_bits,
|
||||
evals,
|
||||
betas[i],
|
||||
&common_data
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@ -1,23 +1,90 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::field::extension_field::target::ExtensionTarget;
|
||||
use crate::field::extension_field::Extendable;
|
||||
use crate::field::field_types::RichField;
|
||||
use crate::gates::interpolation::InterpolationGate;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::iop::target::Target;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
|
||||
pub(crate) trait InterpolationGate<F: RichField + Extendable<D>, const D: usize>:
|
||||
Gate<F, D> + Copy
|
||||
{
|
||||
fn new(subgroup_bits: usize) -> Self;
|
||||
|
||||
fn num_points(&self) -> usize;
|
||||
|
||||
/// Wire index of the coset shift.
|
||||
fn wire_shift(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn start_values(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
/// Wire indices of the `i`th interpolant value.
|
||||
fn wires_value(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_values() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_point(&self) -> usize {
|
||||
self.start_values() + self.num_points() * D
|
||||
}
|
||||
|
||||
/// Wire indices of the point to evaluate the interpolant at.
|
||||
fn wires_evaluation_point(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_point();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_value(&self) -> usize {
|
||||
self.start_evaluation_point() + D
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolated value.
|
||||
fn wires_evaluation_value(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_value();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_coeffs(&self) -> usize {
|
||||
self.start_evaluation_value() + D
|
||||
}
|
||||
|
||||
/// The number of routed wires required in the typical usage of this gate, where the points to
|
||||
/// interpolate, the evaluation point, and the corresponding value are all routed.
|
||||
fn num_routed_wires(&self) -> usize {
|
||||
self.start_coeffs()
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolant's `i`th coefficient.
|
||||
fn wires_coeff(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_coeffs() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn end_coeffs(&self) -> usize {
|
||||
self.start_coeffs() + D * self.num_points()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
/// Interpolates a polynomial, whose points are a coset of the multiplicative subgroup with the
|
||||
/// given size, and whose values are given. Returns the evaluation of the interpolant at
|
||||
/// `evaluation_point`.
|
||||
pub fn interpolate_coset(
|
||||
pub(crate) fn interpolate_coset<G: InterpolationGate<F, D>>(
|
||||
&mut self,
|
||||
subgroup_bits: usize,
|
||||
coset_shift: Target,
|
||||
values: &[ExtensionTarget<D>],
|
||||
evaluation_point: ExtensionTarget<D>,
|
||||
) -> ExtensionTarget<D> {
|
||||
let gate = InterpolationGate::new(subgroup_bits);
|
||||
let gate_index = self.add_gate(gate.clone(), vec![]);
|
||||
let gate = G::new(subgroup_bits);
|
||||
let gate_index = self.add_gate(gate, vec![]);
|
||||
self.connect(coset_shift, Target::wire(gate_index, gate.wire_shift()));
|
||||
for (i, &v) in values.iter().enumerate() {
|
||||
self.connect_extension(
|
||||
@ -38,11 +105,14 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::field::extension_field::quadratic::QuadraticExtension;
|
||||
use crate::field::extension_field::quartic::QuarticExtension;
|
||||
use crate::field::extension_field::FieldExtension;
|
||||
use crate::field::field_types::Field;
|
||||
use crate::field::goldilocks_field::GoldilocksField;
|
||||
use crate::field::interpolation::interpolant;
|
||||
use crate::gates::interpolation::HighDegreeInterpolationGate;
|
||||
use crate::gates::low_degree_interpolation::LowDegreeInterpolationGate;
|
||||
use crate::iop::witness::PartialWitness;
|
||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
@ -51,10 +121,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_interpolate() -> Result<()> {
|
||||
type F = GoldilocksField;
|
||||
type FF = QuarticExtension<GoldilocksField>;
|
||||
const D: usize = 2;
|
||||
type FF = QuadraticExtension<GoldilocksField>;
|
||||
let config = CircuitConfig::standard_recursion_config();
|
||||
let pw = PartialWitness::new();
|
||||
let mut builder = CircuitBuilder::<F, 4>::new(config);
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||
|
||||
let subgroup_bits = 2;
|
||||
let len = 1 << subgroup_bits;
|
||||
@ -66,7 +137,7 @@ mod tests {
|
||||
let homogeneous_points = points
|
||||
.iter()
|
||||
.zip(values.iter())
|
||||
.map(|(&a, &b)| (<FF as FieldExtension<4>>::from_basefield(a), b))
|
||||
.map(|(&a, &b)| (<FF as FieldExtension<D>>::from_basefield(a), b))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let true_interpolant = interpolant(&homogeneous_points);
|
||||
@ -83,9 +154,21 @@ mod tests {
|
||||
|
||||
let zt = builder.constant_extension(z);
|
||||
|
||||
let eval = builder.interpolate_coset(subgroup_bits, coset_shift_target, &value_targets, zt);
|
||||
let eval_hd = builder.interpolate_coset::<HighDegreeInterpolationGate<F, D>>(
|
||||
subgroup_bits,
|
||||
coset_shift_target,
|
||||
&value_targets,
|
||||
zt,
|
||||
);
|
||||
let eval_ld = builder.interpolate_coset::<LowDegreeInterpolationGate<F, D>>(
|
||||
subgroup_bits,
|
||||
coset_shift_target,
|
||||
&value_targets,
|
||||
zt,
|
||||
);
|
||||
let true_eval_target = builder.constant_extension(true_eval);
|
||||
builder.connect_extension(eval, true_eval_target);
|
||||
builder.connect_extension(eval_hd, true_eval_target);
|
||||
builder.connect_extension(eval_ld, true_eval_target);
|
||||
|
||||
let data = builder.build();
|
||||
let proof = data.prove(pw)?;
|
||||
|
||||
@ -225,11 +225,12 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::field::goldilocks_field::GoldilocksField;
|
||||
use crate::gadgets::interpolation::InterpolationGate;
|
||||
use crate::gates::arithmetic_extension::ArithmeticExtensionGate;
|
||||
use crate::gates::base_sum::BaseSumGate;
|
||||
use crate::gates::constant::ConstantGate;
|
||||
use crate::gates::gmimc::GMiMCGate;
|
||||
use crate::gates::interpolation::InterpolationGate;
|
||||
use crate::gates::interpolation::HighDegreeInterpolationGate;
|
||||
use crate::gates::noop::NoopGate;
|
||||
|
||||
#[test]
|
||||
@ -244,7 +245,7 @@ mod tests {
|
||||
GateRef::new(ArithmeticExtensionGate { num_ops: 4 }),
|
||||
GateRef::new(BaseSumGate::<4>::new(4)),
|
||||
GateRef::new(GMiMCGate::<F, D, 12>::new()),
|
||||
GateRef::new(InterpolationGate::new(2)),
|
||||
GateRef::new(HighDegreeInterpolationGate::new(2)),
|
||||
];
|
||||
|
||||
let (tree, _, _) = Tree::from_gates(gates.clone());
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::field::extension_field::target::ExtensionTarget;
|
||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||
use crate::field::field_types::RichField;
|
||||
use crate::field::interpolation::interpolant;
|
||||
use crate::gadgets::interpolation::InterpolationGate;
|
||||
use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||
@ -19,77 +20,13 @@ use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||
/// Interpolates a polynomial, whose points are a (base field) coset of the multiplicative subgroup
|
||||
/// with the given size, and whose values are extension field elements, given by input wires.
|
||||
/// Outputs the evaluation of the interpolant at a given (extension field) evaluation point.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct InterpolationGate<F: RichField + Extendable<D>, const D: usize> {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct HighDegreeInterpolationGate<F: RichField + Extendable<D>, const D: usize> {
|
||||
pub subgroup_bits: usize,
|
||||
_phantom: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> InterpolationGate<F, D> {
|
||||
pub fn new(subgroup_bits: usize) -> Self {
|
||||
Self {
|
||||
subgroup_bits,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn num_points(&self) -> usize {
|
||||
1 << self.subgroup_bits
|
||||
}
|
||||
|
||||
/// Wire index of the coset shift.
|
||||
pub fn wire_shift(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn start_values(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
/// Wire indices of the `i`th interpolant value.
|
||||
pub fn wires_value(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_values() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_point(&self) -> usize {
|
||||
self.start_values() + self.num_points() * D
|
||||
}
|
||||
|
||||
/// Wire indices of the point to evaluate the interpolant at.
|
||||
pub fn wires_evaluation_point(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_point();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_value(&self) -> usize {
|
||||
self.start_evaluation_point() + D
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolated value.
|
||||
pub fn wires_evaluation_value(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_value();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_coeffs(&self) -> usize {
|
||||
self.start_evaluation_value() + D
|
||||
}
|
||||
|
||||
/// The number of routed wires required in the typical usage of this gate, where the points to
|
||||
/// interpolate, the evaluation point, and the corresponding value are all routed.
|
||||
pub(crate) fn num_routed_wires(&self) -> usize {
|
||||
self.start_coeffs()
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolant's `i`th coefficient.
|
||||
pub fn wires_coeff(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_coeffs() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> HighDegreeInterpolationGate<F, D> {
|
||||
/// End of wire indices, exclusive.
|
||||
fn end(&self) -> usize {
|
||||
self.start_coeffs() + self.num_points() * D
|
||||
@ -128,7 +65,77 @@ impl<F: RichField + Extendable<D>, const D: usize> InterpolationGate<F, D> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationGate<F, D> {
|
||||
impl<F: RichField + Extendable<D>, const D: usize> InterpolationGate<F, D>
|
||||
for HighDegreeInterpolationGate<F, D>
|
||||
{
|
||||
fn new(subgroup_bits: usize) -> Self {
|
||||
Self {
|
||||
subgroup_bits,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn num_points(&self) -> usize {
|
||||
1 << self.subgroup_bits
|
||||
}
|
||||
|
||||
/// Wire index of the coset shift.
|
||||
fn wire_shift(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn start_values(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
/// Wire indices of the `i`th interpolant value.
|
||||
fn wires_value(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_values() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_point(&self) -> usize {
|
||||
self.start_values() + self.num_points() * D
|
||||
}
|
||||
|
||||
/// Wire indices of the point to evaluate the interpolant at.
|
||||
fn wires_evaluation_point(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_point();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_value(&self) -> usize {
|
||||
self.start_evaluation_point() + D
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolated value.
|
||||
fn wires_evaluation_value(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_value();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_coeffs(&self) -> usize {
|
||||
self.start_evaluation_value() + D
|
||||
}
|
||||
|
||||
/// The number of routed wires required in the typical usage of this gate, where the points to
|
||||
/// interpolate, the evaluation point, and the corresponding value are all routed.
|
||||
fn num_routed_wires(&self) -> usize {
|
||||
self.start_coeffs()
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolant's `i`th coefficient.
|
||||
fn wires_coeff(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_coeffs() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D>
|
||||
for HighDegreeInterpolationGate<F, D>
|
||||
{
|
||||
fn id(&self) -> String {
|
||||
format!("{:?}<D={}>", self, D)
|
||||
}
|
||||
@ -251,7 +258,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for InterpolationG
|
||||
#[derive(Debug)]
|
||||
struct InterpolationGenerator<F: RichField + Extendable<D>, const D: usize> {
|
||||
gate_index: usize,
|
||||
gate: InterpolationGate<F, D>,
|
||||
gate: HighDegreeInterpolationGate<F, D>,
|
||||
_phantom: PhantomData<F>,
|
||||
}
|
||||
|
||||
@ -324,16 +331,17 @@ mod tests {
|
||||
use crate::field::extension_field::quartic::QuarticExtension;
|
||||
use crate::field::field_types::Field;
|
||||
use crate::field::goldilocks_field::GoldilocksField;
|
||||
use crate::gadgets::interpolation::InterpolationGate;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::gates::gate_testing::{test_eval_fns, test_low_degree};
|
||||
use crate::gates::interpolation::InterpolationGate;
|
||||
use crate::gates::interpolation::HighDegreeInterpolationGate;
|
||||
use crate::hash::hash_types::HashOut;
|
||||
use crate::plonk::vars::EvaluationVars;
|
||||
use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||
|
||||
#[test]
|
||||
fn wire_indices() {
|
||||
let gate = InterpolationGate::<GoldilocksField, 4> {
|
||||
let gate = HighDegreeInterpolationGate::<GoldilocksField, 4> {
|
||||
subgroup_bits: 1,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
@ -352,12 +360,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn low_degree() {
|
||||
test_low_degree::<GoldilocksField, _, 4>(InterpolationGate::new(2));
|
||||
test_low_degree::<GoldilocksField, _, 4>(HighDegreeInterpolationGate::new(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_fns() -> Result<()> {
|
||||
test_eval_fns::<GoldilocksField, _, 4>(InterpolationGate::new(2))
|
||||
test_eval_fns::<GoldilocksField, _, 4>(HighDegreeInterpolationGate::new(2))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -368,7 +376,7 @@ mod tests {
|
||||
|
||||
/// Returns the local wires for an interpolation gate for given coeffs, points and eval point.
|
||||
fn get_wires(
|
||||
gate: &InterpolationGate<F, D>,
|
||||
gate: &HighDegreeInterpolationGate<F, D>,
|
||||
shift: F,
|
||||
coeffs: PolynomialCoeffs<FF>,
|
||||
eval_point: FF,
|
||||
@ -390,7 +398,7 @@ mod tests {
|
||||
let shift = F::rand();
|
||||
let coeffs = PolynomialCoeffs::new(vec![FF::rand(), FF::rand()]);
|
||||
let eval_point = FF::rand();
|
||||
let gate = InterpolationGate::<F, D>::new(1);
|
||||
let gate = HighDegreeInterpolationGate::<F, D>::new(1);
|
||||
let vars = EvaluationVars {
|
||||
local_constants: &[],
|
||||
local_wires: &get_wires(&gate, shift, coeffs, eval_point),
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::field::extension_field::algebra::{ExtensionAlgebra, PolynomialCoeffsAlgebra};
|
||||
use crate::field::extension_field::algebra::PolynomialCoeffsAlgebra;
|
||||
use crate::field::extension_field::target::ExtensionTarget;
|
||||
use crate::field::extension_field::{Extendable, FieldExtension};
|
||||
use crate::field::field_types::{Field, RichField};
|
||||
use crate::field::interpolation::interpolant;
|
||||
use crate::gadgets::interpolation::InterpolationGate;
|
||||
use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
||||
@ -19,81 +20,13 @@ use crate::polynomial::polynomial::PolynomialCoeffs;
|
||||
/// Interpolates a polynomial, whose points are a (base field) coset of the multiplicative subgroup
|
||||
/// with the given size, and whose values are extension field elements, given by input wires.
|
||||
/// Outputs the evaluation of the interpolant at a given (extension field) evaluation point.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct LowDegreeInterpolationGate<F: RichField + Extendable<D>, const D: usize> {
|
||||
pub subgroup_bits: usize,
|
||||
_phantom: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> LowDegreeInterpolationGate<F, D> {
|
||||
pub fn new(subgroup_bits: usize) -> Self {
|
||||
Self {
|
||||
subgroup_bits,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn num_points(&self) -> usize {
|
||||
1 << self.subgroup_bits
|
||||
}
|
||||
|
||||
/// Wire index of the coset shift.
|
||||
pub fn wire_shift(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn start_values(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
/// Wire indices of the `i`th interpolant value.
|
||||
pub fn wires_value(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_values() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_point(&self) -> usize {
|
||||
self.start_values() + self.num_points() * D
|
||||
}
|
||||
|
||||
/// Wire indices of the point to evaluate the interpolant at.
|
||||
pub fn wires_evaluation_point(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_point();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_value(&self) -> usize {
|
||||
self.start_evaluation_point() + D
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolated value.
|
||||
pub fn wires_evaluation_value(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_value();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_coeffs(&self) -> usize {
|
||||
self.start_evaluation_value() + D
|
||||
}
|
||||
|
||||
/// The number of routed wires required in the typical usage of this gate, where the points to
|
||||
/// interpolate, the evaluation point, and the corresponding value are all routed.
|
||||
pub(crate) fn num_routed_wires(&self) -> usize {
|
||||
self.start_coeffs()
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolant's `i`th coefficient.
|
||||
pub fn wires_coeff(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_coeffs() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn end_coeffs(&self) -> usize {
|
||||
self.start_coeffs() + D * self.num_points()
|
||||
}
|
||||
|
||||
pub fn powers_init(&self, i: usize) -> usize {
|
||||
debug_assert!(0 < i && i < self.num_points());
|
||||
if i == 1 {
|
||||
@ -123,29 +56,77 @@ impl<F: RichField + Extendable<D>, const D: usize> LowDegreeInterpolationGate<F,
|
||||
// Speed matters here, so we avoid `cyclic_subgroup_coset_known_order` which allocates.
|
||||
g.powers().take(size).map(move |x| x * shift)
|
||||
}
|
||||
}
|
||||
|
||||
/// The domain of the points we're interpolating.
|
||||
fn coset_ext(&self, shift: F::Extension) -> impl Iterator<Item = F::Extension> {
|
||||
let g = F::primitive_root_of_unity(self.subgroup_bits);
|
||||
let size = 1 << self.subgroup_bits;
|
||||
g.powers().take(size).map(move |x| shift.scalar_mul(x))
|
||||
impl<F: RichField + Extendable<D>, const D: usize> InterpolationGate<F, D>
|
||||
for LowDegreeInterpolationGate<F, D>
|
||||
{
|
||||
fn new(subgroup_bits: usize) -> Self {
|
||||
Self {
|
||||
subgroup_bits,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// The domain of the points we're interpolating.
|
||||
fn coset_ext_recursive(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
shift: ExtensionTarget<D>,
|
||||
) -> Vec<ExtensionTarget<D>> {
|
||||
let g = F::primitive_root_of_unity(self.subgroup_bits);
|
||||
let size = 1 << self.subgroup_bits;
|
||||
g.powers()
|
||||
.take(size)
|
||||
.map(move |x| {
|
||||
let subgroup_element = builder.constant(x.into());
|
||||
builder.scalar_mul_ext(subgroup_element, shift)
|
||||
})
|
||||
.collect()
|
||||
fn num_points(&self) -> usize {
|
||||
1 << self.subgroup_bits
|
||||
}
|
||||
|
||||
/// Wire index of the coset shift.
|
||||
fn wire_shift(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn start_values(&self) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
/// Wire indices of the `i`th interpolant value.
|
||||
fn wires_value(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_values() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_point(&self) -> usize {
|
||||
self.start_values() + self.num_points() * D
|
||||
}
|
||||
|
||||
/// Wire indices of the point to evaluate the interpolant at.
|
||||
fn wires_evaluation_point(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_point();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_evaluation_value(&self) -> usize {
|
||||
self.start_evaluation_point() + D
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolated value.
|
||||
fn wires_evaluation_value(&self) -> Range<usize> {
|
||||
let start = self.start_evaluation_value();
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn start_coeffs(&self) -> usize {
|
||||
self.start_evaluation_value() + D
|
||||
}
|
||||
|
||||
/// The number of routed wires required in the typical usage of this gate, where the points to
|
||||
/// interpolate, the evaluation point, and the corresponding value are all routed.
|
||||
fn num_routed_wires(&self) -> usize {
|
||||
self.start_coeffs()
|
||||
}
|
||||
|
||||
/// Wire indices of the interpolant's `i`th coefficient.
|
||||
fn wires_coeff(&self, i: usize) -> Range<usize> {
|
||||
debug_assert!(i < self.num_points());
|
||||
let start = self.start_coeffs() + i * D;
|
||||
start..start + D
|
||||
}
|
||||
|
||||
fn end_coeffs(&self) -> usize {
|
||||
self.start_coeffs() + D * self.num_points()
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,7 +167,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Gate<F, D> for LowDegreeInter
|
||||
constraints.extend(&(value - computed_value).to_basefield_array());
|
||||
}
|
||||
|
||||
let mut evaluation_point_powers = (1..self.num_points())
|
||||
let evaluation_point_powers = (1..self.num_points())
|
||||
.map(|i| vars.get_local_ext_algebra(self.powers_eval(i)))
|
||||
.collect::<Vec<_>>();
|
||||
let evaluation_point = evaluation_point_powers[0];
|
||||
@ -408,11 +389,13 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F>
|
||||
|
||||
let wire_shift = get_local_wire(self.gate.wire_shift());
|
||||
|
||||
for i in 2..self.gate.num_points() {
|
||||
out_buffer.set_wire(
|
||||
local_wire(self.gate.powers_init(i)),
|
||||
wire_shift.exp_u64(i as u64),
|
||||
);
|
||||
for (i, power) in wire_shift
|
||||
.powers()
|
||||
.take(self.gate.num_points())
|
||||
.enumerate()
|
||||
.skip(2)
|
||||
{
|
||||
out_buffer.set_wire(local_wire(self.gate.powers_init(i)), power);
|
||||
}
|
||||
|
||||
// Compute the interpolant.
|
||||
@ -452,6 +435,7 @@ mod tests {
|
||||
use crate::field::extension_field::quartic::QuarticExtension;
|
||||
use crate::field::field_types::Field;
|
||||
use crate::field::goldilocks_field::GoldilocksField;
|
||||
use crate::gadgets::interpolation::InterpolationGate;
|
||||
use crate::gates::gate::Gate;
|
||||
use crate::gates::gate_testing::{test_eval_fns, test_low_degree};
|
||||
use crate::gates::low_degree_interpolation::LowDegreeInterpolationGate;
|
||||
|
||||
@ -687,7 +687,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
marked_targets: self.marked_targets,
|
||||
representative_map: forest.parents,
|
||||
fft_root_table: Some(fft_root_table),
|
||||
instances: self.gate_instances,
|
||||
};
|
||||
|
||||
// The HashSet of gates will have a non-deterministic order. When converting to a Vec, we
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::field::field_types::{Field, RichField};
|
||||
use crate::fri::commitment::PolynomialBatchCommitment;
|
||||
use crate::fri::reduction_strategies::FriReductionStrategy;
|
||||
use crate::fri::{FriConfig, FriParams};
|
||||
use crate::gates::gate::{GateInstance, PrefixedGate};
|
||||
use crate::gates::gate::PrefixedGate;
|
||||
use crate::hash::hash_types::{HashOut, MerkleCapTarget};
|
||||
use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::iop::generator::WitnessGenerator;
|
||||
@ -177,7 +177,6 @@ pub(crate) struct ProverOnlyCircuitData<F: RichField + Extendable<D>, const D: u
|
||||
pub representative_map: Vec<usize>,
|
||||
/// Pre-computed roots for faster FFT.
|
||||
pub fft_root_table: Option<FftRootTable<F>>,
|
||||
pub instances: Vec<GateInstance<F, D>>,
|
||||
}
|
||||
|
||||
/// Circuit data required by the verifier, but not the prover.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user