halo2/halo2_frontend/src/plonk/circuit.rs

201 lines
7.2 KiB
Rust

use crate::circuit::{layouter::SyncDeps, Layouter, Value};
use crate::plonk::{Assigned, Error};
use halo2_middleware::circuit::{Advice, Any, Fixed, Instance};
use halo2_middleware::ff::Field;
pub mod compress_selectors;
pub mod constraint_system;
pub mod expression;
pub use constraint_system::*;
pub use expression::*;
// TODO: Bring ColumnType, Advice, Fixed, Instance and Any here, where Advice has a sealed phase
// Keep a slim copy of those types in middleware.
// https://github.com/privacy-scaling-explorations/halo2/issues/295
/// This trait allows a [`Circuit`] to direct some backend to assign a witness
/// for a constraint system.
pub trait Assignment<F: Field> {
/// Creates a new region and enters into it.
///
/// Panics if we are currently in a region (if `exit_region` was not called).
///
/// Not intended for downstream consumption; use [`Layouter::assign_region`] instead.
///
/// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
fn enter_region<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR;
/// Allows the developer to include an annotation for an specific column within a `Region`.
///
/// This is usually useful for debugging circuit failures.
fn annotate_column<A, AR>(&mut self, annotation: A, column: Column<Any>)
where
A: FnOnce() -> AR,
AR: Into<String>;
/// Exits the current region.
///
/// Panics if we are not currently in a region (if `enter_region` was not called).
///
/// Not intended for downstream consumption; use [`Layouter::assign_region`] instead.
///
/// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
fn exit_region(&mut self);
/// Enables a selector at the given row.
fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
row: usize,
) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>;
/// Queries the cell of an instance column at a particular absolute row.
///
/// Returns the cell's value, if known.
fn query_instance(&self, column: Column<Instance>, row: usize) -> Result<Value<F>, Error>;
/// Assign an advice column value (witness)
fn assign_advice<V, VR, A, AR>(
&mut self,
annotation: A,
column: Column<Advice>,
row: usize,
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Value<VR>,
VR: Into<Assigned<F>>,
A: FnOnce() -> AR,
AR: Into<String>;
/// Assign a fixed value
fn assign_fixed<V, VR, A, AR>(
&mut self,
annotation: A,
column: Column<Fixed>,
row: usize,
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Value<VR>,
VR: Into<Assigned<F>>,
A: FnOnce() -> AR,
AR: Into<String>;
/// Assign two cells to have the same value
fn copy(
&mut self,
left_column: Column<Any>,
left_row: usize,
right_column: Column<Any>,
right_row: usize,
) -> Result<(), Error>;
/// Fills a fixed `column` starting from the given `row` with value `to`.
fn fill_from_row(
&mut self,
column: Column<Fixed>,
row: usize,
to: Value<Assigned<F>>,
) -> Result<(), Error>;
/// Queries the value of the given challenge.
///
/// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried.
fn get_challenge(&self, challenge: Challenge) -> Value<F>;
/// Creates a new (sub)namespace and enters into it.
///
/// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
///
/// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR;
/// Exits out of the existing namespace.
///
/// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
///
/// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace
fn pop_namespace(&mut self, gadget_name: Option<String>);
}
/// A floor planning strategy for a circuit.
///
/// The floor planner is chip-agnostic and applies its strategy to the circuit it is used
/// within.
pub trait FloorPlanner {
/// Given the provided `cs`, synthesize the given circuit.
///
/// `constants` is the list of fixed columns that the layouter may use to assign
/// global constant values. These columns will all have been equality-enabled.
///
/// Internally, a floor planner will perform the following operations:
/// - Instantiate a [`Layouter`] for this floor planner.
/// - Perform any necessary setup or measurement tasks, which may involve one or more
/// calls to `Circuit::default().synthesize(config, &mut layouter)`.
/// - Call `circuit.synthesize(config, &mut layouter)` exactly once.
fn synthesize<F: Field, CS: Assignment<F> + SyncDeps, C: Circuit<F>>(
cs: &mut CS,
circuit: &C,
config: C::Config,
constants: Vec<Column<Fixed>>,
) -> Result<(), Error>;
}
/// This is a trait that circuits provide implementations for so that the
/// backend prover can ask the circuit to synthesize using some given
/// [`ConstraintSystem`] implementation.
pub trait Circuit<F: Field> {
/// This is a configuration object that stores things like columns.
type Config: Clone;
/// The floor planner used for this circuit. This is an associated type of the
/// `Circuit` trait because its behaviour is circuit-critical.
type FloorPlanner: FloorPlanner;
/// Optional circuit configuration parameters. Requires the `circuit-params` feature.
#[cfg(feature = "circuit-params")]
type Params: Default;
/// Returns a copy of this circuit with no witness values (i.e. all witnesses set to
/// `None`). For most circuits, this will be equal to `Self::default()`.
fn without_witnesses(&self) -> Self;
/// Returns a reference to the parameters that should be used to configure the circuit.
/// Requires the `circuit-params` feature.
#[cfg(feature = "circuit-params")]
fn params(&self) -> Self::Params {
Self::Params::default()
}
/// The circuit is given an opportunity to describe the exact gate
/// arrangement, column arrangement, etc. Takes a runtime parameter. The default
/// implementation calls `configure` ignoring the `_params` argument in order to easily support
/// circuits that don't use configuration parameters.
#[cfg(feature = "circuit-params")]
fn configure_with_params(
meta: &mut ConstraintSystem<F>,
_params: Self::Params,
) -> Self::Config {
Self::configure(meta)
}
/// The circuit is given an opportunity to describe the exact gate
/// arrangement, column arrangement, etc.
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config;
/// Given the provided `cs`, synthesize the circuit. The concrete type of
/// the caller will be different depending on the context, and they may or
/// may not expect to have a witness present.
fn synthesize(&self, config: Self::Config, layouter: impl Layouter<F>) -> Result<(), Error>;
}