2021-06-07 06:46:31 -07:00
|
|
|
use std::fmt;
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
use ff::Field;
|
|
|
|
|
2021-06-07 06:46:31 -07:00
|
|
|
use crate::{
|
2021-06-21 11:10:59 -07:00
|
|
|
circuit::{
|
2021-07-26 17:34:51 -07:00
|
|
|
floor_planner::single_pass::SimpleTableLayouter,
|
|
|
|
layouter::{RegionColumn, RegionLayouter, RegionShape, TableLayouter},
|
|
|
|
Cell, Layouter, Region, RegionIndex, RegionStart, Table,
|
2021-06-21 11:10:59 -07:00
|
|
|
},
|
2021-07-08 13:44:01 -07:00
|
|
|
plonk::{
|
2021-07-21 09:19:35 -07:00
|
|
|
Advice, Any, Assigned, Assignment, Circuit, Column, Error, Fixed, FloorPlanner, Instance,
|
2021-07-27 07:46:37 -07:00
|
|
|
Selector, TableColumn,
|
2021-07-08 13:44:01 -07:00
|
|
|
},
|
2021-06-07 06:46:31 -07:00
|
|
|
};
|
|
|
|
|
2021-06-08 03:03:29 -07:00
|
|
|
mod strategy;
|
|
|
|
|
2021-06-21 11:10:59 -07:00
|
|
|
/// The version 1 [`FloorPlanner`] provided by `halo2`.
|
2021-06-07 06:46:31 -07:00
|
|
|
///
|
2021-06-21 11:10:59 -07:00
|
|
|
/// - No column optimizations are performed. Circuit configuration is left entirely to the
|
|
|
|
/// circuit designer.
|
|
|
|
/// - A dual-pass layouter is used to measures regions prior to assignment.
|
|
|
|
/// - Regions are measured as rectangles, bounded on the cells they assign.
|
|
|
|
/// - Regions are layed out using a greedy first-fit strategy, after sorting regions by
|
|
|
|
/// their "advice area" (number of advice columns * rows).
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct V1;
|
|
|
|
|
|
|
|
struct V1Plan<'a, F: Field, CS: Assignment<F> + 'a> {
|
2021-06-07 06:46:31 -07:00
|
|
|
cs: &'a mut CS,
|
|
|
|
/// Stores the starting row for each region.
|
|
|
|
regions: Vec<RegionStart>,
|
2021-07-20 08:09:24 -07:00
|
|
|
/// Stores the constants to be assigned, and the cells to which they are copied.
|
|
|
|
constants: Vec<(Assigned<F>, Cell)>,
|
2021-07-26 17:34:51 -07:00
|
|
|
/// Stores the table fixed columns.
|
2021-07-27 07:46:37 -07:00
|
|
|
table_columns: Vec<TableColumn>,
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
|
2021-06-21 11:10:59 -07:00
|
|
|
impl<'a, F: Field, CS: Assignment<F> + 'a> fmt::Debug for V1Plan<'a, F, CS> {
|
2021-06-07 06:46:31 -07:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-06-21 11:10:59 -07:00
|
|
|
f.debug_struct("floor_planner::V1Plan").finish()
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-21 11:10:59 -07:00
|
|
|
impl<'a, F: Field, CS: Assignment<F>> V1Plan<'a, F, CS> {
|
2021-06-07 06:46:31 -07:00
|
|
|
/// Creates a new v1 layouter.
|
|
|
|
pub fn new(cs: &'a mut CS) -> Result<Self, Error> {
|
2021-06-21 11:10:59 -07:00
|
|
|
let ret = V1Plan {
|
2021-06-07 06:46:31 -07:00
|
|
|
cs,
|
|
|
|
regions: vec![],
|
2021-07-20 08:09:24 -07:00
|
|
|
constants: vec![],
|
2021-07-26 17:34:51 -07:00
|
|
|
table_columns: vec![],
|
2021-06-07 06:46:31 -07:00
|
|
|
};
|
|
|
|
Ok(ret)
|
|
|
|
}
|
2021-06-21 11:10:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FloorPlanner for V1 {
|
|
|
|
fn synthesize<F: Field, CS: Assignment<F>, C: Circuit<F>>(
|
|
|
|
cs: &mut CS,
|
|
|
|
circuit: &C,
|
|
|
|
config: C::Config,
|
2021-07-20 08:09:24 -07:00
|
|
|
constants: Vec<Column<Fixed>>,
|
2021-06-21 11:10:59 -07:00
|
|
|
) -> Result<(), Error> {
|
|
|
|
let mut plan = V1Plan::new(cs)?;
|
2021-06-07 06:46:31 -07:00
|
|
|
|
|
|
|
// First pass: measure the regions within the circuit.
|
|
|
|
let mut measure = MeasurementPass::new();
|
|
|
|
{
|
|
|
|
let pass = &mut measure;
|
2021-06-21 11:10:59 -07:00
|
|
|
circuit
|
|
|
|
.without_witnesses()
|
|
|
|
.synthesize(config.clone(), V1Pass::<_, CS>::measure(pass))?;
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
|
2021-07-20 08:09:24 -07:00
|
|
|
// Planning:
|
|
|
|
// - Position the regions.
|
|
|
|
let (regions, column_allocations) = strategy::slot_in_biggest_advice_first(measure.regions);
|
|
|
|
plan.regions = regions;
|
|
|
|
|
|
|
|
// - Determine how many rows our planned circuit will require.
|
|
|
|
let first_unassigned_row = column_allocations
|
|
|
|
.iter()
|
|
|
|
.map(|(_, a)| a.unbounded_interval_start())
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
// - Position the constants within those rows.
|
|
|
|
let fixed_allocations: Vec<_> = constants
|
|
|
|
.into_iter()
|
|
|
|
.map(|c| {
|
|
|
|
(
|
|
|
|
c,
|
|
|
|
column_allocations
|
2021-07-21 09:19:35 -07:00
|
|
|
.get(&Column::<Any>::from(c).into())
|
2021-07-20 08:09:24 -07:00
|
|
|
.cloned()
|
|
|
|
.unwrap_or_default(),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let constant_positions = || {
|
|
|
|
fixed_allocations.iter().flat_map(|(c, a)| {
|
|
|
|
let c = *c;
|
|
|
|
a.free_intervals(0, Some(first_unassigned_row))
|
|
|
|
.flat_map(move |e| e.range().unwrap().map(move |i| (c, i)))
|
|
|
|
})
|
|
|
|
};
|
2021-06-07 06:46:31 -07:00
|
|
|
|
2021-07-20 08:09:24 -07:00
|
|
|
// Second pass:
|
|
|
|
// - Assign the regions.
|
2021-06-21 11:10:59 -07:00
|
|
|
let mut assign = AssignmentPass::new(&mut plan);
|
2021-06-07 06:46:31 -07:00
|
|
|
{
|
|
|
|
let pass = &mut assign;
|
2021-06-21 11:10:59 -07:00
|
|
|
circuit.synthesize(config, V1Pass::assign(pass))?;
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
|
2021-07-20 08:09:24 -07:00
|
|
|
// - Assign the constants.
|
|
|
|
if constant_positions().count() < plan.constants.len() {
|
|
|
|
return Err(Error::NotEnoughColumnsForConstants);
|
|
|
|
}
|
|
|
|
for ((fixed_column, fixed_row), (value, advice)) in
|
|
|
|
constant_positions().zip(plan.constants.into_iter())
|
|
|
|
{
|
|
|
|
plan.cs.assign_fixed(
|
|
|
|
|| format!("Constant({:?})", value.evaluate()),
|
|
|
|
fixed_column,
|
|
|
|
fixed_row,
|
|
|
|
|| Ok(value),
|
|
|
|
)?;
|
|
|
|
plan.cs.copy(
|
|
|
|
fixed_column.into(),
|
|
|
|
fixed_row,
|
|
|
|
advice.column,
|
|
|
|
*plan.regions[*advice.region_index] + advice.row_offset,
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
2021-06-07 06:46:31 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-06-20 16:10:16 -07:00
|
|
|
enum Pass<'p, 'a, F: Field, CS: Assignment<F> + 'a> {
|
2021-06-07 06:46:31 -07:00
|
|
|
Measurement(&'p mut MeasurementPass),
|
|
|
|
Assignment(&'p mut AssignmentPass<'p, 'a, F, CS>),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A single pass of the [`V1`] layouter.
|
|
|
|
#[derive(Debug)]
|
2021-06-20 16:10:16 -07:00
|
|
|
pub struct V1Pass<'p, 'a, F: Field, CS: Assignment<F> + 'a>(Pass<'p, 'a, F, CS>);
|
2021-06-07 06:46:31 -07:00
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<'p, 'a, F: Field, CS: Assignment<F> + 'a> V1Pass<'p, 'a, F, CS> {
|
2021-06-07 06:46:31 -07:00
|
|
|
fn measure(pass: &'p mut MeasurementPass) -> Self {
|
|
|
|
V1Pass(Pass::Measurement(pass))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assign(pass: &'p mut AssignmentPass<'p, 'a, F, CS>) -> Self {
|
|
|
|
V1Pass(Pass::Assignment(pass))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<'p, 'a, F: Field, CS: Assignment<F> + 'a> Layouter<F> for V1Pass<'p, 'a, F, CS> {
|
2021-06-07 06:46:31 -07:00
|
|
|
type Root = Self;
|
|
|
|
|
|
|
|
fn assign_region<A, AR, N, NR>(&mut self, name: N, assignment: A) -> Result<AR, Error>
|
|
|
|
where
|
|
|
|
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
|
|
|
|
N: Fn() -> NR,
|
|
|
|
NR: Into<String>,
|
|
|
|
{
|
|
|
|
match &mut self.0 {
|
|
|
|
Pass::Measurement(pass) => pass.assign_region(assignment),
|
|
|
|
Pass::Assignment(pass) => pass.assign_region(name, assignment),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-26 17:34:51 -07:00
|
|
|
fn assign_table<A, N, NR>(&mut self, name: N, assignment: A) -> Result<(), Error>
|
|
|
|
where
|
|
|
|
A: FnMut(Table<'_, F>) -> Result<(), Error>,
|
|
|
|
N: Fn() -> NR,
|
|
|
|
NR: Into<String>,
|
|
|
|
{
|
|
|
|
match &mut self.0 {
|
|
|
|
Pass::Measurement(_) => Ok(()),
|
|
|
|
Pass::Assignment(pass) => pass.assign_table(name, assignment),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 13:44:01 -07:00
|
|
|
fn constrain_instance(
|
|
|
|
&mut self,
|
|
|
|
cell: Cell,
|
|
|
|
instance: Column<Instance>,
|
|
|
|
row: usize,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
match &mut self.0 {
|
|
|
|
Pass::Measurement(_) => Ok(()),
|
|
|
|
Pass::Assignment(pass) => pass.constrain_instance(cell, instance, row),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-07 06:46:31 -07:00
|
|
|
fn get_root(&mut self) -> &mut Self::Root {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
|
|
|
where
|
|
|
|
NR: Into<String>,
|
|
|
|
N: FnOnce() -> NR,
|
|
|
|
{
|
2021-06-08 04:40:16 -07:00
|
|
|
if let Pass::Assignment(pass) = &mut self.0 {
|
2021-06-21 11:10:59 -07:00
|
|
|
pass.plan.cs.push_namespace(name_fn);
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_namespace(&mut self, gadget_name: Option<String>) {
|
2021-06-08 04:40:16 -07:00
|
|
|
if let Pass::Assignment(pass) = &mut self.0 {
|
2021-06-21 11:10:59 -07:00
|
|
|
pass.plan.cs.pop_namespace(gadget_name);
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Measures the circuit.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct MeasurementPass {
|
|
|
|
regions: Vec<RegionShape>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MeasurementPass {
|
|
|
|
fn new() -> Self {
|
|
|
|
MeasurementPass { regions: vec![] }
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
fn assign_region<F: Field, A, AR>(&mut self, mut assignment: A) -> Result<AR, Error>
|
2021-06-07 06:46:31 -07:00
|
|
|
where
|
|
|
|
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
|
|
|
|
{
|
|
|
|
let region_index = self.regions.len();
|
|
|
|
|
|
|
|
// Get shape of the region.
|
|
|
|
let mut shape = RegionShape::new(region_index.into());
|
|
|
|
let result = {
|
|
|
|
let region: &mut dyn RegionLayouter<F> = &mut shape;
|
|
|
|
assignment(region.into())
|
|
|
|
}?;
|
|
|
|
self.regions.push(shape);
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Assigns the circuit.
|
|
|
|
#[derive(Debug)]
|
2021-06-20 16:10:16 -07:00
|
|
|
pub struct AssignmentPass<'p, 'a, F: Field, CS: Assignment<F> + 'a> {
|
2021-06-21 11:10:59 -07:00
|
|
|
plan: &'p mut V1Plan<'a, F, CS>,
|
2021-06-07 06:46:31 -07:00
|
|
|
/// Counter tracking which region we need to assign next.
|
|
|
|
region_index: usize,
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<'p, 'a, F: Field, CS: Assignment<F> + 'a> AssignmentPass<'p, 'a, F, CS> {
|
2021-06-21 11:10:59 -07:00
|
|
|
fn new(plan: &'p mut V1Plan<'a, F, CS>) -> Self {
|
2021-06-07 06:46:31 -07:00
|
|
|
AssignmentPass {
|
2021-06-21 11:10:59 -07:00
|
|
|
plan,
|
2021-06-07 06:46:31 -07:00
|
|
|
region_index: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assign_region<A, AR, N, NR>(&mut self, name: N, mut assignment: A) -> Result<AR, Error>
|
|
|
|
where
|
|
|
|
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
|
|
|
|
N: Fn() -> NR,
|
|
|
|
NR: Into<String>,
|
|
|
|
{
|
|
|
|
// Get the next region we are assigning.
|
|
|
|
let region_index = self.region_index;
|
|
|
|
self.region_index += 1;
|
|
|
|
|
2021-06-21 11:10:59 -07:00
|
|
|
self.plan.cs.enter_region(name);
|
|
|
|
let mut region = V1Region::new(self.plan, region_index.into());
|
2021-06-07 06:46:31 -07:00
|
|
|
let result = {
|
|
|
|
let region: &mut dyn RegionLayouter<F> = &mut region;
|
|
|
|
assignment(region.into())
|
|
|
|
}?;
|
2021-06-21 11:10:59 -07:00
|
|
|
self.plan.cs.exit_region();
|
2021-06-07 06:46:31 -07:00
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
2021-07-08 13:44:01 -07:00
|
|
|
|
2021-07-26 17:34:51 -07:00
|
|
|
fn assign_table<A, AR, N, NR>(&mut self, name: N, mut assignment: A) -> Result<AR, Error>
|
|
|
|
where
|
|
|
|
A: FnMut(Table<'_, F>) -> Result<AR, Error>,
|
|
|
|
N: Fn() -> NR,
|
|
|
|
NR: Into<String>,
|
|
|
|
{
|
2021-07-27 09:49:52 -07:00
|
|
|
// Maintenance hazard: there is near-duplicate code in `SingleChipLayouter::assign_table`.
|
|
|
|
|
2021-07-26 17:34:51 -07:00
|
|
|
// Assign table cells.
|
|
|
|
self.plan.cs.enter_region(name);
|
|
|
|
let mut table = SimpleTableLayouter::new(self.plan.cs, &self.plan.table_columns);
|
|
|
|
let result = {
|
|
|
|
let table: &mut dyn TableLayouter<F> = &mut table;
|
|
|
|
assignment(table.into())
|
|
|
|
}?;
|
|
|
|
let default_and_assigned = table.default_and_assigned;
|
|
|
|
self.plan.cs.exit_region();
|
|
|
|
|
|
|
|
// Check that all table columns have the same length `first_unused`,
|
|
|
|
// and all cells up to that length are assigned.
|
|
|
|
let first_unused = {
|
|
|
|
match default_and_assigned
|
|
|
|
.values()
|
|
|
|
.map(|(_, assigned)| {
|
|
|
|
if assigned.iter().all(|b| *b) {
|
|
|
|
Some(assigned.len())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.reduce(|acc, item| match (acc, item) {
|
|
|
|
(Some(a), Some(b)) if a == b => Some(a),
|
|
|
|
_ => None,
|
|
|
|
}) {
|
|
|
|
Some(Some(len)) => len,
|
|
|
|
_ => return Err(Error::SynthesisError), // TODO better error
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Record these columns so that we can prevent them from being used again.
|
|
|
|
for column in default_and_assigned.keys() {
|
2021-07-27 08:04:27 -07:00
|
|
|
self.plan.table_columns.push(*column);
|
2021-07-26 17:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for (col, (default_val, _)) in default_and_assigned {
|
|
|
|
// default_val must be Some because we must have assigned
|
|
|
|
// at least one cell in each column, and in that case we checked
|
|
|
|
// that all cells up to first_unused were assigned.
|
|
|
|
self.plan
|
|
|
|
.cs
|
2021-07-27 07:46:37 -07:00
|
|
|
.fill_from_row(col.inner(), first_unused, default_val.unwrap())?;
|
2021-07-26 17:34:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
2021-07-08 13:44:01 -07:00
|
|
|
fn constrain_instance(
|
|
|
|
&mut self,
|
|
|
|
cell: Cell,
|
|
|
|
instance: Column<Instance>,
|
|
|
|
row: usize,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
self.plan.cs.copy(
|
|
|
|
cell.column,
|
|
|
|
*self.plan.regions[*cell.region_index] + cell.row_offset,
|
|
|
|
instance.into(),
|
|
|
|
row,
|
|
|
|
)
|
|
|
|
}
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
struct V1Region<'r, 'a, F: Field, CS: Assignment<F> + 'a> {
|
2021-06-21 11:10:59 -07:00
|
|
|
plan: &'r mut V1Plan<'a, F, CS>,
|
2021-06-07 06:46:31 -07:00
|
|
|
region_index: RegionIndex,
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> fmt::Debug for V1Region<'r, 'a, F, CS> {
|
2021-06-07 06:46:31 -07:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("V1Region")
|
2021-06-21 11:10:59 -07:00
|
|
|
.field("plan", &self.plan)
|
2021-06-07 06:46:31 -07:00
|
|
|
.field("region_index", &self.region_index)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> V1Region<'r, 'a, F, CS> {
|
2021-06-21 11:10:59 -07:00
|
|
|
fn new(plan: &'r mut V1Plan<'a, F, CS>, region_index: RegionIndex) -> Self {
|
|
|
|
V1Region { plan, region_index }
|
2021-06-07 06:46:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> RegionLayouter<F> for V1Region<'r, 'a, F, CS> {
|
2021-06-07 06:46:31 -07:00
|
|
|
fn enable_selector<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
selector: &Selector,
|
|
|
|
offset: usize,
|
|
|
|
) -> Result<(), Error> {
|
2021-06-21 11:10:59 -07:00
|
|
|
self.plan.cs.enable_selector(
|
2021-06-07 06:46:31 -07:00
|
|
|
annotation,
|
|
|
|
selector,
|
2021-06-21 11:10:59 -07:00
|
|
|
*self.plan.regions[*self.region_index] + offset,
|
2021-06-07 06:46:31 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assign_advice<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
column: Column<Advice>,
|
|
|
|
offset: usize,
|
2021-06-11 09:41:27 -07:00
|
|
|
to: &'v mut (dyn FnMut() -> Result<Assigned<F>, Error> + 'v),
|
2021-06-07 06:46:31 -07:00
|
|
|
) -> Result<Cell, Error> {
|
2021-06-21 11:10:59 -07:00
|
|
|
self.plan.cs.assign_advice(
|
2021-06-07 06:46:31 -07:00
|
|
|
annotation,
|
|
|
|
column,
|
2021-06-21 11:10:59 -07:00
|
|
|
*self.plan.regions[*self.region_index] + offset,
|
2021-06-07 06:46:31 -07:00
|
|
|
to,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(Cell {
|
|
|
|
region_index: self.region_index,
|
|
|
|
row_offset: offset,
|
|
|
|
column: column.into(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-20 08:09:24 -07:00
|
|
|
fn assign_advice_from_constant<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
column: Column<Advice>,
|
|
|
|
offset: usize,
|
|
|
|
constant: Assigned<F>,
|
|
|
|
) -> Result<Cell, Error> {
|
|
|
|
let advice = self.assign_advice(annotation, column, offset, &mut || Ok(constant))?;
|
2021-07-20 09:19:47 -07:00
|
|
|
self.constrain_constant(advice, constant)?;
|
2021-07-20 08:09:24 -07:00
|
|
|
|
|
|
|
Ok(advice)
|
|
|
|
}
|
|
|
|
|
2021-07-08 13:44:01 -07:00
|
|
|
fn assign_advice_from_instance<'v>(
|
|
|
|
&mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
instance: Column<Instance>,
|
|
|
|
row: usize,
|
|
|
|
advice: Column<Advice>,
|
|
|
|
offset: usize,
|
|
|
|
) -> Result<(Cell, Option<F>), Error> {
|
|
|
|
let value = self.plan.cs.query_instance(instance, row)?;
|
|
|
|
|
|
|
|
let cell = self.assign_advice(annotation, advice, offset, &mut || {
|
|
|
|
value.ok_or(Error::SynthesisError).map(|v| v.into())
|
|
|
|
})?;
|
|
|
|
|
|
|
|
self.plan.cs.copy(
|
|
|
|
cell.column,
|
|
|
|
*self.plan.regions[*cell.region_index] + cell.row_offset,
|
|
|
|
instance.into(),
|
|
|
|
row,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok((cell, value))
|
|
|
|
}
|
|
|
|
|
2021-06-07 06:46:31 -07:00
|
|
|
fn assign_fixed<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
column: Column<Fixed>,
|
|
|
|
offset: usize,
|
2021-06-11 09:41:27 -07:00
|
|
|
to: &'v mut (dyn FnMut() -> Result<Assigned<F>, Error> + 'v),
|
2021-06-07 06:46:31 -07:00
|
|
|
) -> Result<Cell, Error> {
|
2021-06-21 11:10:59 -07:00
|
|
|
self.plan.cs.assign_fixed(
|
2021-06-07 06:46:31 -07:00
|
|
|
annotation,
|
|
|
|
column,
|
2021-06-21 11:10:59 -07:00
|
|
|
*self.plan.regions[*self.region_index] + offset,
|
2021-06-07 06:46:31 -07:00
|
|
|
to,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(Cell {
|
|
|
|
region_index: self.region_index,
|
|
|
|
row_offset: offset,
|
|
|
|
column: column.into(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-20 09:19:47 -07:00
|
|
|
fn constrain_constant(&mut self, cell: Cell, constant: Assigned<F>) -> Result<(), Error> {
|
|
|
|
self.plan.constants.push((constant, cell));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error> {
|
2021-06-21 11:10:59 -07:00
|
|
|
self.plan.cs.copy(
|
2021-06-07 06:46:31 -07:00
|
|
|
left.column,
|
2021-06-21 11:10:59 -07:00
|
|
|
*self.plan.regions[*left.region_index] + left.row_offset,
|
2021-06-07 06:46:31 -07:00
|
|
|
right.column,
|
2021-06-21 11:10:59 -07:00
|
|
|
*self.plan.regions[*right.region_index] + right.row_offset,
|
2021-06-07 06:46:31 -07:00
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2021-07-21 08:43:18 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use pasta_curves::vesta;
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
dev::MockProver,
|
|
|
|
plonk::{Advice, Circuit, Column, Error},
|
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn not_enough_columns_for_constants() {
|
|
|
|
struct MyCircuit {}
|
|
|
|
|
|
|
|
impl Circuit<vesta::Scalar> for MyCircuit {
|
|
|
|
type Config = Column<Advice>;
|
|
|
|
type FloorPlanner = super::V1;
|
|
|
|
|
|
|
|
fn without_witnesses(&self) -> Self {
|
|
|
|
MyCircuit {}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn configure(meta: &mut crate::plonk::ConstraintSystem<vesta::Scalar>) -> Self::Config {
|
|
|
|
meta.advice_column()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn synthesize(
|
|
|
|
&self,
|
|
|
|
config: Self::Config,
|
|
|
|
mut layouter: impl crate::circuit::Layouter<vesta::Scalar>,
|
|
|
|
) -> Result<(), crate::plonk::Error> {
|
|
|
|
layouter.assign_region(
|
|
|
|
|| "assign constant",
|
|
|
|
|mut region| {
|
|
|
|
region.assign_advice_from_constant(
|
|
|
|
|| "one",
|
|
|
|
config,
|
|
|
|
0,
|
|
|
|
vesta::Scalar::one(),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let circuit = MyCircuit {};
|
2021-05-26 14:28:11 -07:00
|
|
|
assert!(matches!(
|
2021-07-21 08:43:18 -07:00
|
|
|
MockProver::run(3, &circuit, vec![]).unwrap_err(),
|
|
|
|
Error::NotEnoughColumnsForConstants,
|
2021-05-26 14:28:11 -07:00
|
|
|
));
|
2021-07-21 08:43:18 -07:00
|
|
|
}
|
|
|
|
}
|