use std::convert::TryInto; use std::marker::PhantomData; use std::ops::Range; use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; 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, const D: usize> { num_points: usize, _phantom: PhantomData, } impl, const D: usize> 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) -> Range { debug_assert!(i < self.num_points); let start = self.start_values() + i * EXT_SIZE; start..start + EXT_SIZE } fn start_evaluation_point(&self) -> usize { self.start_values() + self.num_points * EXT_SIZE } /// Wire indices of the point to evaluate the interpolant at. pub fn wires_evaluation_point(&self) -> Range { let start = self.start_evaluation_point(); start..start + EXT_SIZE } fn start_evaluation_value(&self) -> usize { self.start_evaluation_point() + EXT_SIZE } /// Wire indices of the interpolated value. pub fn wires_evaluation_value(&self) -> Range { let start = self.start_evaluation_value(); start..start + EXT_SIZE } fn start_coeffs(&self) -> usize { self.start_evaluation_value() + EXT_SIZE } /// Wire indices of the interpolant's `i`th coefficient. pub fn wires_coeff(&self, i: usize) -> Range { debug_assert!(i < self.num_points); let start = self.start_coeffs() + i * EXT_SIZE; start..start + EXT_SIZE } fn end(&self) -> usize { self.start_coeffs() + self.num_points * EXT_SIZE } } impl, const D: usize> 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 { let mut constraints = Vec::with_capacity(self.num_constraints()); let x_eval = F::Extension::from_basefield_array( vars.local_wires[self.wires_evaluation_point()].try_into().unwrap()); let x_eval_powers = x_eval.powers().take(self.num_points); // TODO constraints } fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec { todo!() } fn generators( &self, gate_index: usize, _local_constants: &[F], ) -> Vec>> { let gen = QuarticInterpolationGenerator:: { gate_index, num_points: self.num_points, _phantom: PhantomData, }; vec![Box::new(gen)] } fn num_wires(&self) -> usize { self.end() } fn num_constants(&self) -> usize { 0 } fn degree(&self) -> usize { self.num_points - 1 } fn num_constraints(&self) -> usize { todo!() } } struct QuarticInterpolationGenerator, const D: usize> { gate_index: usize, num_points: usize, _phantom: PhantomData, } impl, const D: usize> 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::field::crandall_field::CrandallField; use crate::gates::gate::Gate; use crate::gates::interpolation_quartic::QuarticInterpolationGate; #[test] fn wire_indices_2_points() { 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), 2..6); assert_eq!(gate.wires_value(1), 6..10); assert_eq!(gate.wires_evaluation_point(), 10..14); assert_eq!(gate.wires_evaluation_value(), 14..18); assert_eq!(gate.wires_coeff(0), 18..22); assert_eq!(gate.wires_coeff(1), 22..26); assert_eq!(gate.num_wires(), 26); } #[test] fn wire_indices_4_points() { let gate = QuarticInterpolationGate:: { num_points: 4, _phantom: PhantomData, }; assert_eq!(gate.num_wires(), 44); } }