halo2_proofs/
dev.rs

1//! Tools for developing circuits.
2
3use std::collections::HashMap;
4use std::collections::HashSet;
5use std::iter;
6use std::ops::{Add, Mul, Neg, Range};
7
8use ff::Field;
9
10use crate::plonk::Assigned;
11use crate::{
12    circuit,
13    plonk::{
14        permutation, Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Expression,
15        Fixed, FloorPlanner, Instance, Selector,
16    },
17};
18
19pub mod metadata;
20mod util;
21
22mod failure;
23pub use failure::{FailureLocation, VerifyFailure};
24
25pub mod cost;
26pub use cost::CircuitCost;
27
28mod gates;
29pub use gates::CircuitGates;
30
31mod tfp;
32pub use tfp::TracingFloorPlanner;
33
34#[cfg(feature = "dev-graph")]
35mod graph;
36
37#[cfg(feature = "dev-graph")]
38#[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))]
39pub use graph::{circuit_dot_graph, layout::CircuitLayout};
40
41#[derive(Debug)]
42struct Region {
43    /// The name of the region. Not required to be unique.
44    name: String,
45    /// The columns involved in this region.
46    columns: HashSet<Column<Any>>,
47    /// The rows that this region starts and ends on, if known.
48    rows: Option<(usize, usize)>,
49    /// The selectors that have been enabled in this region. All other selectors are by
50    /// construction not enabled.
51    enabled_selectors: HashMap<Selector, Vec<usize>>,
52    /// The cells assigned in this region. We store this as a `Vec` so that if any cells
53    /// are double-assigned, they will be visibly darker.
54    cells: Vec<(Column<Any>, usize)>,
55}
56
57impl Region {
58    fn update_extent(&mut self, column: Column<Any>, row: usize) {
59        self.columns.insert(column);
60
61        // The region start is the earliest row assigned to.
62        // The region end is the latest row assigned to.
63        let (mut start, mut end) = self.rows.unwrap_or((row, row));
64        if row < start {
65            // The first row assigned was not at start 0 within the region.
66            start = row;
67        }
68        if row > end {
69            end = row;
70        }
71        self.rows = Some((start, end));
72    }
73}
74
75/// The value of a particular cell within the circuit.
76#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77enum CellValue<F: Field> {
78    // An unassigned cell.
79    Unassigned,
80    // A cell that has been assigned a value.
81    Assigned(F),
82    // A unique poisoned cell.
83    Poison(usize),
84}
85
86/// A value within an expression.
87#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
88enum Value<F: Field> {
89    Real(F),
90    Poison,
91}
92
93impl<F: Field> From<CellValue<F>> for Value<F> {
94    fn from(value: CellValue<F>) -> Self {
95        match value {
96            // Cells that haven't been explicitly assigned to, default to zero.
97            CellValue::Unassigned => Value::Real(F::ZERO),
98            CellValue::Assigned(v) => Value::Real(v),
99            CellValue::Poison(_) => Value::Poison,
100        }
101    }
102}
103
104impl<F: Field> Neg for Value<F> {
105    type Output = Self;
106
107    fn neg(self) -> Self::Output {
108        match self {
109            Value::Real(a) => Value::Real(-a),
110            _ => Value::Poison,
111        }
112    }
113}
114
115impl<F: Field> Add for Value<F> {
116    type Output = Self;
117
118    fn add(self, rhs: Self) -> Self::Output {
119        match (self, rhs) {
120            (Value::Real(a), Value::Real(b)) => Value::Real(a + b),
121            _ => Value::Poison,
122        }
123    }
124}
125
126impl<F: Field> Mul for Value<F> {
127    type Output = Self;
128
129    fn mul(self, rhs: Self) -> Self::Output {
130        match (self, rhs) {
131            (Value::Real(a), Value::Real(b)) => Value::Real(a * b),
132            // If poison is multiplied by zero, then we treat the poison as unconstrained
133            // and we don't propagate it.
134            (Value::Real(x), Value::Poison) | (Value::Poison, Value::Real(x))
135                if x.is_zero_vartime() =>
136            {
137                Value::Real(F::ZERO)
138            }
139            _ => Value::Poison,
140        }
141    }
142}
143
144impl<F: Field> Mul<F> for Value<F> {
145    type Output = Self;
146
147    fn mul(self, rhs: F) -> Self::Output {
148        match self {
149            Value::Real(lhs) => Value::Real(lhs * rhs),
150            // If poison is multiplied by zero, then we treat the poison as unconstrained
151            // and we don't propagate it.
152            Value::Poison if rhs.is_zero_vartime() => Value::Real(F::ZERO),
153            _ => Value::Poison,
154        }
155    }
156}
157
158/// A test prover for debugging circuits.
159///
160/// The normal proving process, when applied to a buggy circuit implementation, might
161/// return proofs that do not validate when they should, but it can't indicate anything
162/// other than "something is invalid". `MockProver` can be used to figure out _why_ these
163/// are invalid: it stores all the private inputs along with the circuit internals, and
164/// then checks every constraint manually.
165///
166/// # Examples
167///
168/// ```
169/// use group::ff::PrimeField;
170/// use halo2_proofs::{
171///     circuit::{Layouter, SimpleFloorPlanner, Value},
172///     dev::{FailureLocation, MockProver, VerifyFailure},
173///     pasta::Fp,
174///     plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Selector},
175///     poly::Rotation,
176/// };
177/// const K: u32 = 5;
178///
179/// #[derive(Copy, Clone)]
180/// struct MyConfig {
181///     a: Column<Advice>,
182///     b: Column<Advice>,
183///     c: Column<Advice>,
184///     s: Selector,
185/// }
186///
187/// #[derive(Clone, Default)]
188/// struct MyCircuit {
189///     a: Value<u64>,
190///     b: Value<u64>,
191/// }
192///
193/// impl<F: PrimeField> Circuit<F> for MyCircuit {
194///     type Config = MyConfig;
195///     type FloorPlanner = SimpleFloorPlanner;
196///
197///     fn without_witnesses(&self) -> Self {
198///         Self::default()
199///     }
200///
201///     fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
202///         let a = meta.advice_column();
203///         let b = meta.advice_column();
204///         let c = meta.advice_column();
205///         let s = meta.selector();
206///
207///         meta.create_gate("R1CS constraint", |meta| {
208///             let a = meta.query_advice(a, Rotation::cur());
209///             let b = meta.query_advice(b, Rotation::cur());
210///             let c = meta.query_advice(c, Rotation::cur());
211///             let s = meta.query_selector(s);
212///
213///             // BUG: Should be a * b - c
214///             Some(("buggy R1CS", s * (a * b + c)))
215///         });
216///
217///         MyConfig { a, b, c, s }
218///     }
219///
220///     fn synthesize(&self, config: MyConfig, mut layouter: impl Layouter<F>) -> Result<(), Error> {
221///         layouter.assign_region(|| "Example region", |mut region| {
222///             config.s.enable(&mut region, 0)?;
223///             region.assign_advice(|| "a", config.a, 0, || {
224///                 self.a.map(F::from)
225///             })?;
226///             region.assign_advice(|| "b", config.b, 0, || {
227///                 self.b.map(F::from)
228///             })?;
229///             region.assign_advice(|| "c", config.c, 0, || {
230///                 (self.a * self.b).map(F::from)
231///             })?;
232///             Ok(())
233///         })
234///     }
235/// }
236///
237/// // Assemble the private inputs to the circuit.
238/// let circuit = MyCircuit {
239///     a: Value::known(2),
240///     b: Value::known(4),
241/// };
242///
243/// // This circuit has no public inputs.
244/// let instance = vec![];
245///
246/// let prover = MockProver::<Fp>::run(K, &circuit, instance).unwrap();
247/// assert_eq!(
248///     prover.verify(),
249///     Err(vec![VerifyFailure::ConstraintNotSatisfied {
250///         constraint: ((0, "R1CS constraint").into(), 0, "buggy R1CS").into(),
251///         location: FailureLocation::InRegion {
252///             region: (0, "Example region").into(),
253///             offset: 0,
254///         },
255///         cell_values: vec![
256///             (((Any::Advice, 0).into(), 0).into(), "0x2".to_string()),
257///             (((Any::Advice, 1).into(), 0).into(), "0x4".to_string()),
258///             (((Any::Advice, 2).into(), 0).into(), "0x8".to_string()),
259///         ],
260///     }])
261/// );
262///
263/// // If we provide a too-small K, we get an error.
264/// assert!(matches!(
265///     MockProver::<Fp>::run(2, &circuit, vec![]).unwrap_err(),
266///     Error::NotEnoughRowsAvailable {
267///         current_k,
268///     } if current_k == 2,
269/// ));
270/// ```
271#[derive(Debug)]
272pub struct MockProver<F: Field> {
273    k: u32,
274    n: u32,
275    cs: ConstraintSystem<F>,
276
277    /// The regions in the circuit.
278    regions: Vec<Region>,
279    /// The current region being assigned to. Will be `None` after the circuit has been
280    /// synthesized.
281    current_region: Option<Region>,
282
283    // The fixed cells in the circuit, arranged as [column][row].
284    fixed: Vec<Vec<CellValue<F>>>,
285    // The advice cells in the circuit, arranged as [column][row].
286    advice: Vec<Vec<CellValue<F>>>,
287    // The instance cells in the circuit, arranged as [column][row].
288    instance: Vec<Vec<InstanceValue<F>>>,
289
290    selectors: Vec<Vec<bool>>,
291
292    permutation: permutation::keygen::Assembly,
293
294    // A range of available rows for assignment and copies.
295    usable_rows: Range<usize>,
296}
297
298#[derive(Debug, Clone, PartialEq, Eq)]
299enum InstanceValue<F: Field> {
300    Assigned(F),
301    Padding,
302}
303
304impl<F: Field> InstanceValue<F> {
305    fn value(&self) -> F {
306        match self {
307            InstanceValue::Assigned(v) => *v,
308            InstanceValue::Padding => F::ZERO,
309        }
310    }
311}
312
313impl<F: Field> Assignment<F> for MockProver<F> {
314    fn enter_region<NR, N>(&mut self, name: N)
315    where
316        NR: Into<String>,
317        N: FnOnce() -> NR,
318    {
319        assert!(self.current_region.is_none());
320        self.current_region = Some(Region {
321            name: name().into(),
322            columns: HashSet::default(),
323            rows: None,
324            enabled_selectors: HashMap::default(),
325            cells: vec![],
326        });
327    }
328
329    fn exit_region(&mut self) {
330        self.regions.push(self.current_region.take().unwrap());
331    }
332
333    fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
334    where
335        A: FnOnce() -> AR,
336        AR: Into<String>,
337    {
338        if !self.usable_rows.contains(&row) {
339            return Err(Error::not_enough_rows_available(self.k));
340        }
341
342        // Track that this selector was enabled. We require that all selectors are enabled
343        // inside some region (i.e. no floating selectors).
344        self.current_region
345            .as_mut()
346            .unwrap()
347            .enabled_selectors
348            .entry(*selector)
349            .or_default()
350            .push(row);
351
352        self.selectors[selector.0][row] = true;
353
354        Ok(())
355    }
356
357    fn query_instance(
358        &self,
359        column: Column<Instance>,
360        row: usize,
361    ) -> Result<circuit::Value<F>, Error> {
362        if !self.usable_rows.contains(&row) {
363            return Err(Error::not_enough_rows_available(self.k));
364        }
365
366        self.instance
367            .get(column.index())
368            .and_then(|column| column.get(row))
369            .map(|v| circuit::Value::known(v.value()))
370            .ok_or(Error::BoundsFailure)
371    }
372
373    fn assign_advice<V, VR, A, AR>(
374        &mut self,
375        _: A,
376        column: Column<Advice>,
377        row: usize,
378        to: V,
379    ) -> Result<(), Error>
380    where
381        V: FnOnce() -> circuit::Value<VR>,
382        VR: Into<Assigned<F>>,
383        A: FnOnce() -> AR,
384        AR: Into<String>,
385    {
386        if !self.usable_rows.contains(&row) {
387            return Err(Error::not_enough_rows_available(self.k));
388        }
389
390        if let Some(region) = self.current_region.as_mut() {
391            region.update_extent(column.into(), row);
392            region.cells.push((column.into(), row));
393        }
394
395        *self
396            .advice
397            .get_mut(column.index())
398            .and_then(|v| v.get_mut(row))
399            .ok_or(Error::BoundsFailure)? =
400            CellValue::Assigned(to().into_field().evaluate().assign()?);
401
402        Ok(())
403    }
404
405    fn assign_fixed<V, VR, A, AR>(
406        &mut self,
407        _: A,
408        column: Column<Fixed>,
409        row: usize,
410        to: V,
411    ) -> Result<(), Error>
412    where
413        V: FnOnce() -> circuit::Value<VR>,
414        VR: Into<Assigned<F>>,
415        A: FnOnce() -> AR,
416        AR: Into<String>,
417    {
418        if !self.usable_rows.contains(&row) {
419            return Err(Error::not_enough_rows_available(self.k));
420        }
421
422        if let Some(region) = self.current_region.as_mut() {
423            region.update_extent(column.into(), row);
424            region.cells.push((column.into(), row));
425        }
426
427        *self
428            .fixed
429            .get_mut(column.index())
430            .and_then(|v| v.get_mut(row))
431            .ok_or(Error::BoundsFailure)? =
432            CellValue::Assigned(to().into_field().evaluate().assign()?);
433
434        Ok(())
435    }
436
437    fn copy(
438        &mut self,
439        left_column: Column<Any>,
440        left_row: usize,
441        right_column: Column<Any>,
442        right_row: usize,
443    ) -> Result<(), crate::plonk::Error> {
444        if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
445            return Err(Error::not_enough_rows_available(self.k));
446        }
447
448        self.permutation
449            .copy(left_column, left_row, right_column, right_row)
450    }
451
452    fn fill_from_row(
453        &mut self,
454        col: Column<Fixed>,
455        from_row: usize,
456        to: circuit::Value<Assigned<F>>,
457    ) -> Result<(), Error> {
458        if !self.usable_rows.contains(&from_row) {
459            return Err(Error::not_enough_rows_available(self.k));
460        }
461
462        for row in self.usable_rows.clone().skip(from_row) {
463            self.assign_fixed(|| "", col, row, || to)?;
464        }
465
466        Ok(())
467    }
468
469    fn push_namespace<NR, N>(&mut self, _: N)
470    where
471        NR: Into<String>,
472        N: FnOnce() -> NR,
473    {
474        // TODO: Do something with namespaces :)
475    }
476
477    fn pop_namespace(&mut self, _: Option<String>) {
478        // TODO: Do something with namespaces :)
479    }
480}
481
482impl<F: Field + Ord> MockProver<F> {
483    /// Runs a synthetic keygen-and-prove operation on the given circuit, collecting data
484    /// about the constraints and their assignments.
485    pub fn run<ConcreteCircuit: Circuit<F>>(
486        k: u32,
487        circuit: &ConcreteCircuit,
488        instance: Vec<Vec<F>>,
489    ) -> Result<Self, Error> {
490        let n = 1 << k;
491
492        let mut cs = ConstraintSystem::default();
493        let config = ConcreteCircuit::configure(&mut cs);
494        let cs = cs;
495
496        if n < cs.minimum_rows() {
497            return Err(Error::not_enough_rows_available(k));
498        }
499
500        if instance.len() != cs.num_instance_columns {
501            return Err(Error::InvalidInstances);
502        }
503
504        let instance = instance
505            .into_iter()
506            .map(|instance| {
507                if instance.len() > n - (cs.blinding_factors() + 1) {
508                    return Err(Error::InstanceTooLarge);
509                }
510
511                let mut instance_values = vec![InstanceValue::Padding; n];
512                for (idx, value) in instance.into_iter().enumerate() {
513                    instance_values[idx] = InstanceValue::Assigned(value);
514                }
515
516                Ok(instance_values)
517            })
518            .collect::<Result<Vec<_>, _>>()?;
519
520        // Fixed columns contain no blinding factors.
521        let fixed = vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns];
522        let selectors = vec![vec![false; n]; cs.num_selectors];
523        // Advice columns contain blinding factors.
524        let blinding_factors = cs.blinding_factors();
525        let usable_rows = n - (blinding_factors + 1);
526        let advice = vec![
527            {
528                let mut column = vec![CellValue::Unassigned; n];
529                // Poison unusable rows.
530                for (i, cell) in column.iter_mut().enumerate().skip(usable_rows) {
531                    *cell = CellValue::Poison(i);
532                }
533                column
534            };
535            cs.num_advice_columns
536        ];
537        let permutation = permutation::keygen::Assembly::new(n, &cs.permutation);
538        let constants = cs.constants.clone();
539
540        let mut prover = MockProver {
541            k,
542            n: n as u32,
543            cs,
544            regions: vec![],
545            current_region: None,
546            fixed,
547            advice,
548            instance,
549            selectors,
550            permutation,
551            usable_rows: 0..usable_rows,
552        };
553
554        ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?;
555
556        let (cs, selector_polys) = prover.cs.compress_selectors(prover.selectors.clone());
557        prover.cs = cs;
558        prover.fixed.extend(selector_polys.into_iter().map(|poly| {
559            let mut v = vec![CellValue::Unassigned; n];
560            for (v, p) in v.iter_mut().zip(&poly[..]) {
561                *v = CellValue::Assigned(*p);
562            }
563            v
564        }));
565
566        Ok(prover)
567    }
568
569    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
570    /// the reasons that the circuit is not satisfied.
571    ///
572    /// Note: When writing positive tests (i.e. checking that a circuit is valid), prefer using
573    /// [`MockProver::assert_satisfied`] which provides more readable error output. This method
574    /// is primarily intended for writing negative tests to check that specific invalid circuit
575    /// constructions fail with expected errors.
576    pub fn verify(&self) -> Result<(), Vec<VerifyFailure>> {
577        let n = self.n as i32;
578
579        // Check that within each region, all cells used in instantiated gates have been
580        // assigned to.
581        let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| {
582            r.enabled_selectors.iter().flat_map(move |(selector, at)| {
583                // Find the gates enabled by this selector
584                self.cs
585                    .gates
586                    .iter()
587                    // Assume that if a queried selector is enabled, the user wants to use the
588                    // corresponding gate in some way.
589                    //
590                    // TODO: This will trip up on the reverse case, where leaving a selector
591                    // un-enabled keeps a gate enabled. We could alternatively require that
592                    // every selector is explicitly enabled or disabled on every row? But that
593                    // seems messy and confusing.
594                    .enumerate()
595                    .filter(move |(_, g)| g.queried_selectors().contains(selector))
596                    .flat_map(move |(gate_index, gate)| {
597                        at.iter().flat_map(move |selector_row| {
598                            // Selectors are queried with no rotation.
599                            let gate_row = *selector_row as i32;
600
601                            gate.queried_cells().iter().filter_map(move |cell| {
602                                // Determine where this cell should have been assigned.
603                                let cell_row = ((gate_row + n + cell.rotation.0) % n) as usize;
604
605                                match cell.column.column_type() {
606                                    Any::Instance => {
607                                        // Handle instance cells, which are not in the region.
608                                        let instance_value =
609                                            &self.instance[cell.column.index()][cell_row];
610                                        match instance_value {
611                                            InstanceValue::Assigned(_) => None,
612                                            _ => Some(VerifyFailure::InstanceCellNotAssigned {
613                                                gate: (gate_index, gate.name()).into(),
614                                                region: (r_i, r.name.clone()).into(),
615                                                gate_offset: *selector_row,
616                                                column: cell.column.try_into().unwrap(),
617                                                row: cell_row,
618                                            }),
619                                        }
620                                    }
621                                    _ => {
622                                        // Check that it was assigned!
623                                        if r.cells.contains(&(cell.column, cell_row)) {
624                                            None
625                                        } else {
626                                            Some(VerifyFailure::CellNotAssigned {
627                                                gate: (gate_index, gate.name()).into(),
628                                                region: (r_i, r.name.clone()).into(),
629                                                gate_offset: *selector_row,
630                                                column: cell.column,
631                                                offset: cell_row as isize
632                                                    - r.rows.unwrap().0 as isize,
633                                            })
634                                        }
635                                    }
636                                }
637                            })
638                        })
639                    })
640            })
641        });
642
643        // Check that all gates are satisfied for all rows.
644        let gate_errors =
645            self.cs
646                .gates
647                .iter()
648                .enumerate()
649                .flat_map(|(gate_index, gate)| {
650                    // We iterate from n..2n so we can just reduce to handle wrapping.
651                    (n..(2 * n)).flat_map(move |row| {
652                        gate.polynomials().iter().enumerate().filter_map(
653                            move |(poly_index, poly)| match poly.evaluate(
654                                &|scalar| Value::Real(scalar),
655                                &|_| panic!("virtual selectors are removed during optimization"),
656                                &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
657                                &util::load(n, row, &self.cs.advice_queries, &self.advice),
658                                &util::load_instance(
659                                    n,
660                                    row,
661                                    &self.cs.instance_queries,
662                                    &self.instance,
663                                ),
664                                &|a| -a,
665                                &|a, b| a + b,
666                                &|a, b| a * b,
667                                &|a, scalar| a * scalar,
668                            ) {
669                                Value::Real(x) if x.is_zero_vartime() => None,
670                                Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied {
671                                    constraint: (
672                                        (gate_index, gate.name()).into(),
673                                        poly_index,
674                                        gate.constraint_name(poly_index),
675                                    )
676                                        .into(),
677                                    location: FailureLocation::find_expressions(
678                                        &self.cs,
679                                        &self.regions,
680                                        (row - n) as usize,
681                                        Some(poly).into_iter(),
682                                    ),
683                                    cell_values: util::cell_values(
684                                        gate,
685                                        poly,
686                                        &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
687                                        &util::load(n, row, &self.cs.advice_queries, &self.advice),
688                                        &util::load_instance(
689                                            n,
690                                            row,
691                                            &self.cs.instance_queries,
692                                            &self.instance,
693                                        ),
694                                    ),
695                                }),
696                                Value::Poison => Some(VerifyFailure::ConstraintPoisoned {
697                                    constraint: (
698                                        (gate_index, gate.name()).into(),
699                                        poly_index,
700                                        gate.constraint_name(poly_index),
701                                    )
702                                        .into(),
703                                }),
704                            },
705                        )
706                    })
707                });
708
709        // Check that all lookups exist in their respective tables.
710        let lookup_errors =
711            self.cs
712                .lookups
713                .iter()
714                .enumerate()
715                .flat_map(|(lookup_index, lookup)| {
716                    let load = |expression: &Expression<F>, row| {
717                        expression.evaluate(
718                            &|scalar| Value::Real(scalar),
719                            &|_| panic!("virtual selectors are removed during optimization"),
720                            &|query| {
721                                let query = self.cs.fixed_queries[query.index];
722                                let column_index = query.0.index();
723                                let rotation = query.1 .0;
724                                self.fixed[column_index]
725                                    [(row as i32 + n + rotation) as usize % n as usize]
726                                    .into()
727                            },
728                            &|query| {
729                                let query = self.cs.advice_queries[query.index];
730                                let column_index = query.0.index();
731                                let rotation = query.1 .0;
732                                self.advice[column_index]
733                                    [(row as i32 + n + rotation) as usize % n as usize]
734                                    .into()
735                            },
736                            &|query| {
737                                let query = self.cs.instance_queries[query.index];
738                                let column_index = query.0.index();
739                                let rotation = query.1 .0;
740                                Value::Real(
741                                    self.instance[column_index]
742                                        [(row as i32 + n + rotation) as usize % n as usize]
743                                        .value(),
744                                )
745                            },
746                            &|a| -a,
747                            &|a, b| a + b,
748                            &|a, b| a * b,
749                            &|a, scalar| a * scalar,
750                        )
751                    };
752
753                    assert!(lookup.table_expressions.len() == lookup.input_expressions.len());
754                    assert!(self.usable_rows.end > 0);
755
756                    // We optimize on the basis that the table might have been filled so that the last
757                    // usable row now has the fill contents (it doesn't matter if there was no filling).
758                    // Note that this "fill row" necessarily exists in the table, and we use that fact to
759                    // slightly simplify the optimization: we're only trying to check that all input rows
760                    // are contained in the table, and so we can safely just drop input rows that
761                    // match the fill row.
762                    let fill_row: Vec<_> = lookup
763                        .table_expressions
764                        .iter()
765                        .map(move |c| load(c, self.usable_rows.end - 1))
766                        .collect();
767
768                    // In the real prover, the lookup expressions are never enforced on
769                    // unusable rows, due to the (1 - (l_last(X) + l_blind(X))) term.
770                    let mut table: Vec<Vec<_>> = self
771                        .usable_rows
772                        .clone()
773                        .filter_map(|table_row| {
774                            let t = lookup
775                                .table_expressions
776                                .iter()
777                                .map(move |c| load(c, table_row))
778                                .collect();
779
780                            if t != fill_row {
781                                Some(t)
782                            } else {
783                                None
784                            }
785                        })
786                        .collect();
787                    table.sort_unstable();
788
789                    let mut inputs: Vec<(Vec<_>, usize)> = self
790                        .usable_rows
791                        .clone()
792                        .filter_map(|input_row| {
793                            let t = lookup
794                                .input_expressions
795                                .iter()
796                                .map(move |c| load(c, input_row))
797                                .collect();
798
799                            if t != fill_row {
800                                // Also keep track of the original input row, since we're going to sort.
801                                Some((t, input_row))
802                            } else {
803                                None
804                            }
805                        })
806                        .collect();
807                    inputs.sort_unstable();
808
809                    let mut i = 0;
810                    inputs
811                        .iter()
812                        .filter_map(move |(input, input_row)| {
813                            while i < table.len() && &table[i] < input {
814                                i += 1;
815                            }
816                            if i == table.len() || &table[i] > input {
817                                assert!(table.binary_search(input).is_err());
818
819                                Some(VerifyFailure::Lookup {
820                                    lookup_index,
821                                    location: FailureLocation::find_expressions(
822                                        &self.cs,
823                                        &self.regions,
824                                        *input_row,
825                                        lookup.input_expressions.iter(),
826                                    ),
827                                })
828                            } else {
829                                None
830                            }
831                        })
832                        .collect::<Vec<_>>()
833                });
834
835        // Check that permutations preserve the original values of the cells.
836        let perm_errors = {
837            // Original values of columns involved in the permutation.
838            let original = |column, row| {
839                self.cs
840                    .permutation
841                    .get_columns()
842                    .get(column)
843                    .map(|c: &Column<Any>| match c.column_type() {
844                        Any::Advice => self.advice[c.index()][row],
845                        Any::Fixed => self.fixed[c.index()][row],
846                        Any::Instance => {
847                            let cell: &InstanceValue<F> = &self.instance[c.index()][row];
848                            CellValue::Assigned(cell.value())
849                        }
850                    })
851                    .unwrap()
852            };
853
854            // Iterate over each column of the permutation
855            self.permutation
856                .mapping
857                .iter()
858                .enumerate()
859                .flat_map(move |(column, values)| {
860                    // Iterate over each row of the column to check that the cell's
861                    // value is preserved by the mapping.
862                    values.iter().enumerate().filter_map(move |(row, cell)| {
863                        let original_cell = original(column, row);
864                        let permuted_cell = original(cell.0, cell.1);
865                        if original_cell == permuted_cell {
866                            None
867                        } else {
868                            let columns = self.cs.permutation.get_columns();
869                            let column = columns.get(column).unwrap();
870                            Some(VerifyFailure::Permutation {
871                                column: (*column).into(),
872                                location: FailureLocation::find(
873                                    &self.regions,
874                                    row,
875                                    Some(column).into_iter().cloned().collect(),
876                                ),
877                            })
878                        }
879                    })
880                })
881        };
882
883        let mut errors: Vec<_> = iter::empty()
884            .chain(selector_errors)
885            .chain(gate_errors)
886            .chain(lookup_errors)
887            .chain(perm_errors)
888            .collect();
889        if errors.is_empty() {
890            Ok(())
891        } else {
892            // Remove any duplicate `ConstraintPoisoned` errors (we check all unavailable
893            // rows in case the trigger is row-specific, but the error message only points
894            // at the constraint).
895            errors.dedup_by(|a, b| match (a, b) {
896                (
897                    a @ VerifyFailure::ConstraintPoisoned { .. },
898                    b @ VerifyFailure::ConstraintPoisoned { .. },
899                ) => a == b,
900                _ => false,
901            });
902            Err(errors)
903        }
904    }
905
906    /// Panics if the circuit being checked by this `MockProver` is not satisfied.
907    ///
908    /// Any verification failures will be pretty-printed to stderr before the function
909    /// panics.
910    ///
911    /// Apart from the stderr output, this method is equivalent to:
912    /// ```ignore
913    /// assert_eq!(prover.verify(), Ok(()));
914    /// ```
915    pub fn assert_satisfied(&self) {
916        if let Err(errs) = self.verify() {
917            for err in errs {
918                err.emit(self);
919                eprintln!();
920            }
921            panic!("circuit was not satisfied");
922        }
923    }
924}
925
926#[cfg(test)]
927mod tests {
928    use group::ff::Field;
929    use pasta_curves::Fp;
930
931    use super::{FailureLocation, MockProver, VerifyFailure};
932    use crate::{
933        circuit::{Layouter, SimpleFloorPlanner, Value},
934        plonk::{
935            Advice, Any, Circuit, Column, ConstraintSystem, Error, Expression, Selector,
936            TableColumn,
937        },
938        poly::Rotation,
939    };
940
941    #[test]
942    fn unassigned_cell() {
943        const K: u32 = 4;
944
945        #[derive(Clone)]
946        struct FaultyCircuitConfig {
947            a: Column<Advice>,
948            q: Selector,
949        }
950
951        struct FaultyCircuit {}
952
953        impl Circuit<Fp> for FaultyCircuit {
954            type Config = FaultyCircuitConfig;
955            type FloorPlanner = SimpleFloorPlanner;
956
957            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
958                let a = meta.advice_column();
959                let b = meta.advice_column();
960                let q = meta.selector();
961
962                meta.create_gate("Equality check", |cells| {
963                    let a = cells.query_advice(a, Rotation::prev());
964                    let b = cells.query_advice(b, Rotation::cur());
965                    let q = cells.query_selector(q);
966
967                    // If q is enabled, a and b must be assigned to.
968                    vec![q * (a - b)]
969                });
970
971                FaultyCircuitConfig { a, q }
972            }
973
974            fn without_witnesses(&self) -> Self {
975                Self {}
976            }
977
978            fn synthesize(
979                &self,
980                config: Self::Config,
981                mut layouter: impl Layouter<Fp>,
982            ) -> Result<(), Error> {
983                layouter.assign_region(
984                    || "Faulty synthesis",
985                    |mut region| {
986                        // Enable the equality gate.
987                        config.q.enable(&mut region, 1)?;
988
989                        // Assign a = 0.
990                        region.assign_advice(|| "a", config.a, 0, || Value::known(Fp::ZERO))?;
991
992                        // BUG: Forget to assign b = 0! This could go unnoticed during
993                        // development, because cell values default to zero, which in this
994                        // case is fine, but for other assignments would be broken.
995                        Ok(())
996                    },
997                )
998            }
999        }
1000
1001        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
1002        assert_eq!(
1003            prover.verify(),
1004            Err(vec![VerifyFailure::CellNotAssigned {
1005                gate: (0, "Equality check").into(),
1006                region: (0, "Faulty synthesis".to_owned()).into(),
1007                gate_offset: 1,
1008                column: Column::new(1, Any::Advice),
1009                offset: 1,
1010            }])
1011        );
1012    }
1013
1014    #[test]
1015    fn bad_lookup() {
1016        const K: u32 = 4;
1017
1018        #[derive(Clone)]
1019        struct FaultyCircuitConfig {
1020            a: Column<Advice>,
1021            q: Selector,
1022            table: TableColumn,
1023        }
1024
1025        struct FaultyCircuit {}
1026
1027        impl Circuit<Fp> for FaultyCircuit {
1028            type Config = FaultyCircuitConfig;
1029            type FloorPlanner = SimpleFloorPlanner;
1030
1031            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
1032                let a = meta.advice_column();
1033                let q = meta.complex_selector();
1034                let table = meta.lookup_table_column();
1035
1036                meta.lookup(|cells| {
1037                    let a = cells.query_advice(a, Rotation::cur());
1038                    let q = cells.query_selector(q);
1039
1040                    // If q is enabled, a must be in the table.
1041                    // When q is not enabled, lookup the default value instead.
1042                    let not_q = Expression::Constant(Fp::one()) - q.clone();
1043                    let default = Expression::Constant(Fp::from(2));
1044                    vec![(q * a + not_q * default, table)]
1045                });
1046
1047                FaultyCircuitConfig { a, q, table }
1048            }
1049
1050            fn without_witnesses(&self) -> Self {
1051                Self {}
1052            }
1053
1054            fn synthesize(
1055                &self,
1056                config: Self::Config,
1057                mut layouter: impl Layouter<Fp>,
1058            ) -> Result<(), Error> {
1059                layouter.assign_table(
1060                    || "Doubling table",
1061                    |mut table| {
1062                        (1..(1 << (K - 1)))
1063                            .map(|i| {
1064                                table.assign_cell(
1065                                    || format!("table[{}] = {}", i, 2 * i),
1066                                    config.table,
1067                                    i - 1,
1068                                    || Value::known(Fp::from(2 * i as u64)),
1069                                )
1070                            })
1071                            .fold(Ok(()), |acc, res| acc.and(res))
1072                    },
1073                )?;
1074
1075                layouter.assign_region(
1076                    || "Good synthesis",
1077                    |mut region| {
1078                        // Enable the lookup on rows 0 and 1.
1079                        config.q.enable(&mut region, 0)?;
1080                        config.q.enable(&mut region, 1)?;
1081
1082                        // Assign a = 2 and a = 6.
1083                        region.assign_advice(
1084                            || "a = 2",
1085                            config.a,
1086                            0,
1087                            || Value::known(Fp::from(2)),
1088                        )?;
1089                        region.assign_advice(
1090                            || "a = 6",
1091                            config.a,
1092                            1,
1093                            || Value::known(Fp::from(6)),
1094                        )?;
1095
1096                        Ok(())
1097                    },
1098                )?;
1099
1100                layouter.assign_region(
1101                    || "Faulty synthesis",
1102                    |mut region| {
1103                        // Enable the lookup on rows 0 and 1.
1104                        config.q.enable(&mut region, 0)?;
1105                        config.q.enable(&mut region, 1)?;
1106
1107                        // Assign a = 4.
1108                        region.assign_advice(
1109                            || "a = 4",
1110                            config.a,
1111                            0,
1112                            || Value::known(Fp::from(4)),
1113                        )?;
1114
1115                        // BUG: Assign a = 5, which doesn't exist in the table!
1116                        region.assign_advice(
1117                            || "a = 5",
1118                            config.a,
1119                            1,
1120                            || Value::known(Fp::from(5)),
1121                        )?;
1122
1123                        Ok(())
1124                    },
1125                )
1126            }
1127        }
1128
1129        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
1130        assert_eq!(
1131            prover.verify(),
1132            Err(vec![VerifyFailure::Lookup {
1133                lookup_index: 0,
1134                location: FailureLocation::InRegion {
1135                    region: (2, "Faulty synthesis").into(),
1136                    offset: 1,
1137                }
1138            }])
1139        );
1140    }
1141}