From 0c91739b3b551685f26fe1207c0b88f81b420a79 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 17 May 2021 09:06:17 -0700 Subject: [PATCH] [DRAFT] Interpolation gate Over quartic field extension (for now). This would be used in our FRI recursive verifier later, for the consistency check. To summarize the wires, - `n` inputs for the `n` points to interpolate (don't need `4n` since they'll be in the subgroup of the base field) - `4n` inputs for the `n` (extension field) values to interpolate - `4` inputs for the point to evaluate the interpolant at (beta, which will be drawn from the extension field right?) - `4` outputs for the interpolated value - `4n` internal wires for the interpolant's coefficients This definitely isn't the most optimal approach, e.g. we could route in a single "base" point and derive its neighboring points, but just wanted to keep it simple for now. --- src/gates/interpolation_quartic.rs | 169 +++++++++++++++++++++++++++++ src/gates/mod.rs | 1 + 2 files changed, 170 insertions(+) create mode 100644 src/gates/interpolation_quartic.rs diff --git a/src/gates/interpolation_quartic.rs b/src/gates/interpolation_quartic.rs new file mode 100644 index 00000000..57b271ff --- /dev/null +++ b/src/gates/interpolation_quartic.rs @@ -0,0 +1,169 @@ +use std::marker::PhantomData; + +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::quartic::QuarticFieldExtension; +use crate::gates::gate::{Gate, GateRef}; +use crate::generator::{SimpleGenerator, WitnessGenerator}; +use crate::target::Target; +use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::witness::PartialWitness; + +/// The size of the field extension, in terms of number of base elements per extension element. +const EXT_SIZE: usize = 4; + +/// Evaluates the interpolant of some given elements from a quartic field extension. +/// +/// In particular, this gate takes as inputs `num_points` points, `num_points` values, and the point +/// to evaluate the interpolant at. It computes the interpolant and outputs its evaluation at the +/// given point. +#[derive(Debug)] +pub(crate) struct QuarticInterpolationGate { + num_points: usize, + _phantom: PhantomData, +} + +impl QuarticInterpolationGate { + pub fn new(num_points: usize) -> GateRef { + let gate = Self { + num_points, + _phantom: PhantomData, + }; + GateRef::new(gate) + } + + fn start_points(&self) -> usize { + 0 + } + + /// Wire indices of the `i`th interpolant point. + pub fn wire_point(&self, i: usize) -> usize { + debug_assert!(i < self.num_points); + self.start_points() + i + } + + fn start_values(&self) -> usize { + self.start_points() + self.num_points + } + + /// Wire indices of the `i`th interpolant value. + pub fn wires_value(&self, i: usize) -> Vec { + debug_assert!(i < self.num_points); + (0..EXT_SIZE) + .map(|j| self.start_values() + i * EXT_SIZE + j) + .collect() + } + + fn start_interpolated_point(&self) -> usize { + self.start_values() + self.num_points * EXT_SIZE + } + + /// Wire indices of the point to evaluate the interpolant at. + pub fn wires_interpolated_point(&self) -> Vec { + (0..EXT_SIZE).map(|j| self.start_interpolated_point() + j).collect() + } + + fn start_interpolated_value(&self) -> usize { + self.start_interpolated_point() + EXT_SIZE + } + + /// Wire indices of the interpolated value. + pub fn wires_interpolated_value(&self) -> Vec { + (0..EXT_SIZE) + .map(|j| self.start_interpolated_value() + j) + .collect() + } + + fn start_coeffs(&self) -> usize { + self.start_interpolated_value() + EXT_SIZE + } + + /// Wire indices of the interpolant's `i`th coefficient. + pub fn wires_coeff(&self, i: usize) -> Vec { + debug_assert!(i < self.num_points); + (0..EXT_SIZE) + .map(|j| self.start_coeffs() + i * EXT_SIZE + j) + .collect() + } +} + +impl Gate for QuarticInterpolationGate { + fn id(&self) -> String { + let qfe_name = std::any::type_name::(); + format!("{} {:?}", qfe_name, self) + } + + fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { + todo!() + } + + fn eval_unfiltered_recursively( + &self, + builder: &mut CircuitBuilder, + vars: EvaluationTargets, + ) -> Vec { + todo!() + } + + fn generators( + &self, + gate_index: usize, + local_constants: &[QFE::BaseField], + ) -> Vec>> { + todo!() + } + + fn num_wires(&self) -> usize { + todo!() + } + + fn num_constants(&self) -> usize { + todo!() + } + + fn degree(&self) -> usize { + todo!() + } + + fn num_constraints(&self) -> usize { + todo!() + } +} + +struct QuarticInterpolationGenerator { + _phantom: PhantomData, +} + +impl SimpleGenerator + for QuarticInterpolationGenerator +{ + fn dependencies(&self) -> Vec { + todo!() + } + + fn run_once(&self, witness: &PartialWitness) -> PartialWitness { + todo!() + } +} + +#[cfg(test)] +mod tests { + use std::marker::PhantomData; + + use crate::gates::interpolation_quartic::QuarticInterpolationGate; + use crate::field::extension_field::quartic::QuarticCrandallField; + + #[test] + fn wire_indices() { + let gate = QuarticInterpolationGate:: { num_points: 2, _phantom: PhantomData }; + // The exact indices aren't really important, but we want to make sure we don't have any + // overlaps or gaps. + assert_eq!(gate.wire_point(0), 0); + assert_eq!(gate.wire_point(1), 1); + assert_eq!(gate.wires_value(0), vec![2, 3, 4, 5]); + assert_eq!(gate.wires_value(1), vec![6, 7, 8, 9]); + assert_eq!(gate.wires_interpolated_point(), vec![10, 11, 12, 13]); + assert_eq!(gate.wires_interpolated_value(), vec![14, 15, 16, 17]); + assert_eq!(gate.wires_coeff(0), vec![18, 19, 20, 21]); + assert_eq!(gate.wires_coeff(1), vec![22, 23, 24, 25]); + } +} diff --git a/src/gates/mod.rs b/src/gates/mod.rs index f222549d..e35a542d 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -4,4 +4,5 @@ pub(crate) mod fri_consistency_gate; pub(crate) mod gate; pub mod gmimc; pub(crate) mod gmimc_eval; +mod interpolation_quartic; pub(crate) mod noop;