diff --git a/examples/simple-example.rs b/examples/simple-example.rs index 0acc59b..d07779e 100644 --- a/examples/simple-example.rs +++ b/examples/simple-example.rs @@ -136,6 +136,7 @@ impl FieldChip { // ANCHOR: chip-impl impl Chip for FieldChip { type Config = FieldConfig; + type Loaded = (); type Field = F; fn load(_layouter: &mut impl Layouter) -> Result<(), halo2::plonk::Error> { @@ -284,7 +285,7 @@ impl Circuit for MyCircuit { } fn synthesize(&self, cs: &mut impl Assignment, config: Self::Config) -> Result<(), Error> { - let mut layouter = SingleChip::new(cs, config); + let mut layouter = SingleChip::new(cs, config)?; // Load our private values into the circuit. let a = FieldChip::load_private(&mut layouter, self.a)?; diff --git a/src/circuit.rs b/src/circuit.rs index b414211..a6648dd 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -16,16 +16,26 @@ pub mod layouter; /// [`Layouter::config`]. pub trait Chip: Sized { /// A type that holds the configuration for this chip, and any other state it may need - /// during circuit synthesis. + /// during circuit synthesis, that can be derived during [`Circuit::configure`]. + /// + /// [`Circuit::configure`]: crate::plonk::Circuit::configure type Config: fmt::Debug; + /// A type that holds any general chip state that needs to be loaded at the start of + /// [`Circuit::synthesize`]. This might simply be `()` for some chips. + /// + /// [`Circuit::synthesize`]: crate::plonk::Circuit::synthesize + type Loaded: fmt::Debug; + /// The field that the chip is defined over. /// /// This provides a type that the chip's configuration can reference if necessary. type Field: FieldExt; /// Load any fixed configuration for this chip into the circuit. - fn load(layouter: &mut impl Layouter) -> Result<(), Error>; + /// + /// `layouter.loaded()` will panic if called inside this function. + fn load(layouter: &mut impl Layouter) -> Result; } /// Index of a region in a layouter @@ -179,6 +189,12 @@ pub trait Layouter { /// Provides access to the chip configuration. fn config(&self) -> &C::Config; + /// Provides access to general chip state loaded at the beginning of circuit + /// synthesis. + /// + /// Panics if called inside `C::load`. + fn loaded(&self) -> &C::Loaded; + /// Assign a region of gates to an absolute row number. /// /// Inside the closure, the chip may freely use relative offsets; the `Layouter` will @@ -238,6 +254,10 @@ impl<'a, C: Chip, L: Layouter + 'a> Layouter for NamespacedLayouter<'a, C, self.0.config() } + fn loaded(&self) -> &C::Loaded { + self.0.loaded() + } + fn assign_region(&mut self, name: N, assignment: A) -> Result where A: FnMut(Region<'_, C>) -> Result, diff --git a/src/circuit/layouter.rs b/src/circuit/layouter.rs index e9c20d3..ab2065a 100644 --- a/src/circuit/layouter.rs +++ b/src/circuit/layouter.rs @@ -70,6 +70,7 @@ pub trait RegionLayouter: fmt::Debug { pub struct SingleChip<'a, C: Chip, CS: Assignment + 'a> { cs: &'a mut CS, config: C::Config, + loaded: Option, /// Stores the starting row for each region. regions: Vec, /// Stores the first empty row for each column. @@ -89,14 +90,18 @@ impl<'a, C: Chip, CS: Assignment + 'a> fmt::Debug for SingleChip<'a, C impl<'a, C: Chip, CS: Assignment> SingleChip<'a, C, CS> { /// Creates a new single-chip layouter. - pub fn new(cs: &'a mut CS, config: C::Config) -> Self { - SingleChip { + pub fn new(cs: &'a mut CS, config: C::Config) -> Result { + let mut ret = SingleChip { cs, config, + loaded: None, regions: vec![], columns: HashMap::default(), _marker: PhantomData, - } + }; + let loaded = C::load(&mut ret)?; + ret.loaded = Some(loaded); + Ok(ret) } } @@ -107,6 +112,10 @@ impl<'a, C: Chip, CS: Assignment + 'a> Layouter for SingleChip<'a, &self.config } + fn loaded(&self) -> &C::Loaded { + self.loaded.as_ref().expect("We called C::load") + } + fn assign_region(&mut self, name: N, mut assignment: A) -> Result where A: FnMut(Region<'_, C>) -> Result,