diff --git a/halo2-base/src/gates/flex_gate/mod.rs b/halo2-base/src/gates/flex_gate/mod.rs index 9282ed24..d2ba9306 100644 --- a/halo2-base/src/gates/flex_gate/mod.rs +++ b/halo2-base/src/gates/flex_gate/mod.rs @@ -47,6 +47,11 @@ pub struct BasicGateConfig { } impl BasicGateConfig { + /// Constructor + pub fn new(q_enable: Selector, value: Column) -> Self { + Self { q_enable, value, _marker: PhantomData } + } + /// Instantiates a new [BasicGateConfig]. /// /// Assumes `phase` is in the range [0, MAX_PHASE). @@ -103,7 +108,7 @@ pub struct FlexGateConfig { pub basic_gates: Vec>>, /// A [Vec] of [Fixed] [Column]s for allocating constant values. pub constants: Vec>, - /// Max number of rows in flex gate. + /// Max number of usable rows in the circuit. pub max_rows: usize, } diff --git a/halo2-base/src/gates/flex_gate/threads/mod.rs b/halo2-base/src/gates/flex_gate/threads/mod.rs index 870e3df5..675f57ab 100644 --- a/halo2-base/src/gates/flex_gate/threads/mod.rs +++ b/halo2-base/src/gates/flex_gate/threads/mod.rs @@ -11,7 +11,7 @@ mod multi_phase; mod parallelize; /// Thread builder for a single phase -mod single_phase; +pub mod single_phase; pub use multi_phase::{GateStatistics, MultiPhaseCoreManager}; pub use parallelize::parallelize_core; diff --git a/halo2-base/src/gates/flex_gate/threads/single_phase.rs b/halo2-base/src/gates/flex_gate/threads/single_phase.rs index e8aadc24..a0bfd5c3 100644 --- a/halo2-base/src/gates/flex_gate/threads/single_phase.rs +++ b/halo2-base/src/gates/flex_gate/threads/single_phase.rs @@ -140,7 +140,7 @@ impl VirtualRegionManager for SinglePhaseCoreManager { assign_witnesses(&self.threads, config, region, break_points); } else { let mut copy_manager = self.copy_manager.lock().unwrap(); - let break_points = assign_with_constraints( + let break_points = assign_with_constraints::( &self.threads, config, region, @@ -165,13 +165,17 @@ impl VirtualRegionManager for SinglePhaseCoreManager { /// /// For proof generation, see [assign_witnesses]. /// +/// This is generic for a "vertical" custom gate that uses a single column and `ROTATIONS` contiguous rows in that column. +/// +/// ⚠️ Right now we only support "overlaps" where you can have the gate enabled at `offset` and `offset + ROTATIONS - 1`, but not at `offset + delta` where `delta < ROTATIONS - 1`. +/// /// # Inputs /// - `max_rows`: The number of rows that can be used for the assignment. This is the number of rows that are not blinded for zero-knowledge. /// - If `use_unknown` is true, then the advice columns will be assigned as unknowns. /// /// # Assumptions /// - All `basic_gates` are in the same phase. -pub fn assign_with_constraints( +pub fn assign_with_constraints( threads: &[Context], basic_gates: &[BasicGateConfig], region: &mut Region, @@ -206,11 +210,21 @@ pub fn assign_with_constraints( .insert(ContextCell::new(ctx.type_id, ctx.context_id, i), cell); // If selector enabled and row_offset is valid add break point, account for break point overlap, and enforce equality constraint for gate outputs. - if (q && row_offset + 4 > max_rows) || row_offset >= max_rows - 1 { + // ⚠️ This assumes overlap is of form: gate enabled at `i - delta` and `i`, where `delta = ROTATIONS - 1`. We currently do not support `delta < ROTATIONS - 1`. + if (q && row_offset + ROTATIONS > max_rows) || row_offset >= max_rows - 1 { break_points.push(row_offset); row_offset = 0; gate_index += 1; + // safety check: make sure selector is not enabled on `i - delta` for `0 < delta < ROTATIONS - 1` + if ROTATIONS > 1 && i + 2 >= ROTATIONS { + for delta in 1..ROTATIONS - 1 { + assert!( + !ctx.selector[i - delta], + "We do not support overlaps with delta = {delta}" + ); + } + } // when there is a break point, because we may have two gates that overlap at the current cell, we must copy the current cell to the next column for safety basic_gate = basic_gates .get(gate_index)