halo2_base/gates/circuit/
mod.rs1use serde::{Deserialize, Serialize};
2
3use crate::utils::ScalarField;
4use crate::{
5 halo2_proofs::{
6 circuit::{Layouter, SimpleFloorPlanner},
7 plonk::{Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector},
8 },
9 virtual_region::manager::VirtualRegionManager,
10};
11
12use self::builder::BaseCircuitBuilder;
13
14use super::flex_gate::{FlexGateConfig, FlexGateConfigParams};
15use super::range::RangeConfig;
16
17pub mod builder;
19
20#[derive(Clone, Default, Debug, Hash, Serialize, Deserialize)]
23pub struct BaseCircuitParams {
24 pub k: usize,
27 pub num_advice_per_phase: Vec<usize>,
29 pub num_fixed: usize,
31 pub num_lookup_advice_per_phase: Vec<usize>,
34 pub lookup_bits: Option<usize>,
36 #[serde(default)]
38 pub num_instance_columns: usize,
39}
40
41impl BaseCircuitParams {
42 fn gate_params(&self) -> FlexGateConfigParams {
43 FlexGateConfigParams {
44 k: self.k,
45 num_advice_per_phase: self.num_advice_per_phase.clone(),
46 num_fixed: self.num_fixed,
47 }
48 }
49}
50
51#[derive(Clone, Debug)]
53pub struct BaseConfig<F: ScalarField> {
54 pub base: MaybeRangeConfig<F>,
56 pub instance: Vec<Column<Instance>>,
58}
59
60#[derive(Clone, Debug)]
63pub enum MaybeRangeConfig<F: ScalarField> {
64 WithoutRange(FlexGateConfig<F>),
66 WithRange(RangeConfig<F>),
68}
69
70impl<F: ScalarField> BaseConfig<F> {
71 pub fn configure(meta: &mut ConstraintSystem<F>, params: BaseCircuitParams) -> Self {
75 let total_lookup_advice_cols = params.num_lookup_advice_per_phase.iter().sum::<usize>();
76 let base = if params.lookup_bits.is_some() && total_lookup_advice_cols != 0 {
77 MaybeRangeConfig::WithRange(RangeConfig::configure(
79 meta,
80 params.gate_params(),
81 ¶ms.num_lookup_advice_per_phase,
82 params.lookup_bits.unwrap(),
83 ))
84 } else {
85 MaybeRangeConfig::WithoutRange(FlexGateConfig::configure(meta, params.gate_params()))
86 };
87 let instance = (0..params.num_instance_columns)
88 .map(|_| {
89 let inst = meta.instance_column();
90 meta.enable_equality(inst);
91 inst
92 })
93 .collect();
94 Self { base, instance }
95 }
96
97 pub fn gate(&self) -> &FlexGateConfig<F> {
99 match &self.base {
100 MaybeRangeConfig::WithoutRange(config) => config,
101 MaybeRangeConfig::WithRange(config) => &config.gate,
102 }
103 }
104
105 pub fn constants(&self) -> &Vec<Column<Fixed>> {
107 match &self.base {
108 MaybeRangeConfig::WithoutRange(config) => &config.constants,
109 MaybeRangeConfig::WithRange(config) => &config.gate.constants,
110 }
111 }
112
113 pub fn q_lookup(&self) -> &[Option<Selector>] {
116 match &self.base {
117 MaybeRangeConfig::WithoutRange(_) => &[],
118 MaybeRangeConfig::WithRange(config) => &config.q_lookup,
119 }
120 }
121
122 pub fn set_usable_rows(&mut self, usable_rows: usize) {
124 match &mut self.base {
125 MaybeRangeConfig::WithoutRange(config) => config.max_rows = usable_rows,
126 MaybeRangeConfig::WithRange(config) => config.gate.max_rows = usable_rows,
127 }
128 }
129
130 pub fn initialize(&self, layouter: &mut impl Layouter<F>) {
133 if let MaybeRangeConfig::WithRange(config) = &self.base {
135 config.load_lookup_table(layouter).expect("load lookup table should not fail");
136 }
137 }
138}
139
140impl<F: ScalarField> Circuit<F> for BaseCircuitBuilder<F> {
141 type Config = BaseConfig<F>;
142 type FloorPlanner = SimpleFloorPlanner;
143 type Params = BaseCircuitParams;
144
145 fn params(&self) -> Self::Params {
146 self.config_params.clone()
147 }
148
149 fn without_witnesses(&self) -> Self {
151 unimplemented!()
152 }
153
154 fn configure_with_params(meta: &mut ConstraintSystem<F>, params: Self::Params) -> Self::Config {
156 BaseConfig::configure(meta, params)
157 }
158
159 fn configure(_: &mut ConstraintSystem<F>) -> Self::Config {
160 unreachable!("You must use configure_with_params");
161 }
162
163 fn synthesize(
165 &self,
166 config: Self::Config,
167 mut layouter: impl Layouter<F>,
168 ) -> Result<(), Error> {
169 if let MaybeRangeConfig::WithRange(config) = &config.base {
171 config.load_lookup_table(&mut layouter).expect("load lookup table should not fail");
172 }
173 layouter
175 .assign_region(
176 || "BaseCircuitBuilder generated circuit",
177 |mut region| {
178 let usable_rows = config.gate().max_rows;
179 self.core.phase_manager[0].assign_raw(
180 &(config.gate().basic_gates[0].clone(), usable_rows),
181 &mut region,
182 );
183 if let MaybeRangeConfig::WithRange(config) = &config.base {
185 self.assign_lookups_in_phase(config, &mut region, 0);
186 }
187 if !self.core.witness_gen_only() {
189 self.core.copy_manager.assign_raw(config.constants(), &mut region);
190 }
191 Ok(())
192 },
193 )
194 .unwrap();
195
196 self.assign_instances(&config.instance, layouter.namespace(|| "expose"));
197 Ok(())
198 }
199}
200
201#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum CircuitBuilderStage {
204 Keygen,
206 Prover,
208 Mock,
210}
211
212impl CircuitBuilderStage {
213 pub fn witness_gen_only(&self) -> bool {
215 matches!(self, CircuitBuilderStage::Prover)
216 }
217}
218
219impl<F: ScalarField> AsRef<BaseConfig<F>> for BaseConfig<F> {
220 fn as_ref(&self) -> &BaseConfig<F> {
221 self
222 }
223}
224
225impl<F: ScalarField> AsMut<BaseConfig<F>> for BaseConfig<F> {
226 fn as_mut(&mut self) -> &mut BaseConfig<F> {
227 self
228 }
229}