1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
use crate::circuit::{layouter::SyncDeps, Layouter, Value};
use crate::plonk::{Assigned, Error};
use halo2_middleware::circuit::Any;
use halo2_middleware::ff::Field;
use halo2_middleware::poly::Rotation;
pub mod compress_selectors;
pub mod constraint_system;
pub mod expression;
pub use constraint_system::*;
pub use expression::*;
/// A column type
pub trait ColumnType:
'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into<Any>
{
/// Return expression from cell
fn query_cell<F: Field>(&self, index: usize, at: Rotation) -> Expression<F>;
}
/// An advice column
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Advice;
/// A fixed column
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Fixed;
/// An instance column
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Instance;
impl ColumnType for Advice {
fn query_cell<F: Field>(&self, index: usize, at: Rotation) -> Expression<F> {
Expression::Advice(AdviceQuery {
index: None,
column_index: index,
rotation: at,
})
}
}
impl ColumnType for Fixed {
fn query_cell<F: Field>(&self, index: usize, at: Rotation) -> Expression<F> {
Expression::Fixed(FixedQuery {
index: None,
column_index: index,
rotation: at,
})
}
}
impl ColumnType for Instance {
fn query_cell<F: Field>(&self, index: usize, at: Rotation) -> Expression<F> {
Expression::Instance(InstanceQuery {
index: None,
column_index: index,
rotation: at,
})
}
}
impl ColumnType for Any {
fn query_cell<F: Field>(&self, index: usize, at: Rotation) -> Expression<F> {
match self {
Any::Advice => Expression::Advice(AdviceQuery {
index: None,
column_index: index,
rotation: at,
}),
Any::Fixed => Expression::Fixed(FixedQuery {
index: None,
column_index: index,
rotation: at,
}),
Any::Instance => Expression::Instance(InstanceQuery {
index: None,
column_index: index,
rotation: at,
}),
}
}
}
impl From<Advice> for Any {
fn from(_: Advice) -> Any {
Any::Advice
}
}
impl From<Fixed> for Any {
fn from(_: Fixed) -> Any {
Any::Fixed
}
}
impl From<Instance> for Any {
fn from(_: Instance) -> Any {
Any::Instance
}
}
/// 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>;
}