use std::hash::{Hash, Hasher}; use std::sync::Arc; use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::generator::WitnessGenerator; use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A custom gate. pub trait Gate, const D: usize>: 'static + Send + Sync { fn id(&self) -> String; fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec; /// Like `eval_unfiltered`, but specialized for points in the base field. /// /// By default, this just calls `eval_unfiltered`, which treats the point as an extension field /// element. This isn't very efficient. fn eval_unfiltered_base(&self, vars_base: EvaluationVarsBase) -> Vec { let local_constants = &vars_base .local_constants .iter() .map(|c| F::Extension::from_basefield(*c)) .collect::>(); let local_wires = &vars_base .local_wires .iter() .map(|w| F::Extension::from_basefield(*w)) .collect::>(); let vars = EvaluationVars { local_constants, local_wires, }; let values = self.eval_unfiltered(vars); // Each value should be in the base field, i.e. only the degree-zero part should be nonzero. values .into_iter() .map(|value| { // TODO: Change to debug-only once our gate code is mostly finished/stable. assert!(F::Extension::is_in_basefield(&value)); value.to_basefield_array()[0] }) .collect() } fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec>; fn eval_filtered(&self, vars: EvaluationVars) -> Vec { // TODO: Filter self.eval_unfiltered(vars) } /// Like `eval_filtered`, but specialized for points in the base field. fn eval_filtered_base(&self, vars: EvaluationVarsBase) -> Vec { // TODO: Filter self.eval_unfiltered_base(vars) } fn eval_filtered_recursively( &self, builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { // TODO: Filter self.eval_unfiltered_recursively(builder, vars) } fn generators( &self, gate_index: usize, local_constants: &[F], ) -> Vec>>; /// The number of wires used by this gate. fn num_wires(&self) -> usize; /// The number of constants used by this gate. fn num_constants(&self) -> usize; /// The maximum degree among this gate's constraint polynomials. fn degree(&self) -> usize; fn num_constraints(&self) -> usize; } /// A wrapper around an `Rc` which implements `PartialEq`, `Eq` and `Hash` based on gate IDs. #[derive(Clone)] pub struct GateRef, const D: usize>(pub(crate) Arc>); impl, const D: usize> GateRef { pub fn new>(gate: G) -> GateRef { GateRef(Arc::new(gate)) } } impl, const D: usize> PartialEq for GateRef { fn eq(&self, other: &Self) -> bool { self.0.id() == other.0.id() } } impl, const D: usize> Hash for GateRef { fn hash(&self, state: &mut H) { self.0.id().hash(state) } } impl, const D: usize> Eq for GateRef {} /// A gate along with any constants used to configure it. pub struct GateInstance, const D: usize> { pub gate_type: GateRef, pub constants: Vec, }