halo2_axiom/
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};
7use std::sync::Arc;
8
9use blake2b_simd::blake2b;
10use ff::Field;
11use ff::FromUniformBytes;
12
13use crate::plonk::permutation::keygen::Assembly;
14use crate::{
15    circuit,
16    plonk::{
17        permutation,
18        sealed::{self, SealedPhase},
19        Advice, Any, Assigned, Assignment, Challenge, Circuit, Column, ConstraintSystem, Error,
20        Expression, FirstPhase, Fixed, FloorPlanner, Instance, Phase, Selector,
21    },
22};
23
24#[cfg(feature = "multicore")]
25use crate::multicore::{
26    IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator,
27    ParallelSliceMut,
28};
29
30pub mod metadata;
31use metadata::Column as ColumnMetadata;
32mod util;
33
34mod failure;
35pub use failure::{FailureLocation, VerifyFailure};
36
37// pub mod cost;
38// pub use cost::CircuitCost;
39
40mod gates;
41pub use gates::CircuitGates;
42
43mod tfp;
44pub use tfp::TracingFloorPlanner;
45
46// #[cfg(feature = "dev-graph")]
47// mod graph;
48
49// #[cfg(feature = "dev-graph")]
50// #[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))]
51// pub use graph::{circuit_dot_graph, layout::CircuitLayout};
52
53#[derive(Debug)]
54struct Region {
55    /// The name of the region. Not required to be unique.
56    name: String,
57    /// The columns involved in this region.
58    columns: HashSet<Column<Any>>,
59    /// The rows that this region starts and ends on, if known.
60    rows: Option<(usize, usize)>,
61    /// The selectors that have been enabled in this region. All other selectors are by
62    /// construction not enabled.
63    enabled_selectors: HashMap<Selector, Vec<usize>>,
64    /// Annotations given to Advice, Fixed or Instance columns within a region context.
65    annotations: HashMap<ColumnMetadata, String>,
66    /// The cells assigned in this region. We store this as a `Vec` so that if any cells
67    /// are double-assigned, they will be visibly darker.
68    cells: HashMap<(Column<Any>, usize), usize>,
69}
70
71impl Region {
72    fn update_extent(&mut self, column: Column<Any>, row: usize) {
73        self.columns.insert(column);
74
75        // The region start is the earliest row assigned to.
76        // The region end is the latest row assigned to.
77        let (mut start, mut end) = self.rows.unwrap_or((row, row));
78        if row < start {
79            // The first row assigned was not at start 0 within the region.
80            start = row;
81        }
82        if row > end {
83            end = row;
84        }
85        self.rows = Some((start, end));
86    }
87}
88
89/// The value of a particular cell within the circuit.
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
91pub enum CellValue<F: Field> {
92    /// An unassigned cell.
93    Unassigned,
94    /// A cell that has been assigned a value.
95    Assigned(F),
96    /// A unique poisoned cell.
97    Poison(usize),
98}
99
100/// The value of a particular cell within the circuit.
101#[derive(Clone, Debug, PartialEq, Eq)]
102pub enum AdviceCellValue<F: Field> {
103    // A cell that has been assigned a value.
104    Assigned(Arc<Assigned<F>>),
105    // A unique poisoned cell.
106    Poison(usize),
107}
108
109/// A value within an expression.
110#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
111enum Value<F: Field> {
112    Real(F),
113    Poison,
114}
115
116impl<F: Field> From<CellValue<F>> for Value<F> {
117    fn from(value: CellValue<F>) -> Self {
118        match value {
119            // Cells that haven't been explicitly assigned to, default to zero.
120            CellValue::Unassigned => Value::Real(F::ZERO),
121            CellValue::Assigned(v) => Value::Real(v),
122            CellValue::Poison(_) => Value::Poison,
123        }
124    }
125}
126
127impl<F: Field> From<AdviceCellValue<F>> for Value<F> {
128    fn from(value: AdviceCellValue<F>) -> Self {
129        match value {
130            AdviceCellValue::Assigned(v) => Value::Real(v.evaluate()),
131            AdviceCellValue::Poison(_) => Value::Poison,
132        }
133    }
134}
135
136impl<F: Field> Neg for Value<F> {
137    type Output = Self;
138
139    fn neg(self) -> Self::Output {
140        match self {
141            Value::Real(a) => Value::Real(-a),
142            _ => Value::Poison,
143        }
144    }
145}
146
147impl<F: Field> Add for Value<F> {
148    type Output = Self;
149
150    fn add(self, rhs: Self) -> Self::Output {
151        match (self, rhs) {
152            (Value::Real(a), Value::Real(b)) => Value::Real(a + b),
153            _ => Value::Poison,
154        }
155    }
156}
157
158impl<F: Field> Mul for Value<F> {
159    type Output = Self;
160
161    fn mul(self, rhs: Self) -> Self::Output {
162        match (self, rhs) {
163            (Value::Real(a), Value::Real(b)) => Value::Real(a * b),
164            // If poison is multiplied by zero, then we treat the poison as unconstrained
165            // and we don't propagate it.
166            (Value::Real(x), Value::Poison) | (Value::Poison, Value::Real(x))
167                if x.is_zero_vartime() =>
168            {
169                Value::Real(F::ZERO)
170            }
171            _ => Value::Poison,
172        }
173    }
174}
175
176impl<F: Field> Mul<F> for Value<F> {
177    type Output = Self;
178
179    fn mul(self, rhs: F) -> Self::Output {
180        match self {
181            Value::Real(lhs) => Value::Real(lhs * rhs),
182            // If poison is multiplied by zero, then we treat the poison as unconstrained
183            // and we don't propagate it.
184            Value::Poison if rhs.is_zero_vartime() => Value::Real(F::ZERO),
185            _ => Value::Poison,
186        }
187    }
188}
189
190/// A test prover for debugging circuits.
191///
192/// The normal proving process, when applied to a buggy circuit implementation, might
193/// return proofs that do not validate when they should, but it can't indicate anything
194/// other than "something is invalid". `MockProver` can be used to figure out _why_ these
195/// are invalid: it stores all the private inputs along with the circuit internals, and
196/// then checks every constraint manually.
197///
198/// # Examples
199///
200/// ```
201/// use halo2_axiom::{
202///     circuit::{Layouter, SimpleFloorPlanner, Value},
203///     dev::{FailureLocation, MockProver, VerifyFailure},
204///     plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Selector},
205///     poly::Rotation,
206/// };
207/// use ff::PrimeField;
208/// use halo2curves::pasta::Fp;
209/// const K: u32 = 5;
210///
211/// #[derive(Copy, Clone)]
212/// struct MyConfig {
213///     a: Column<Advice>,
214///     b: Column<Advice>,
215///     c: Column<Advice>,
216///     s: Selector,
217/// }
218///
219/// #[derive(Clone, Default)]
220/// struct MyCircuit {
221///     a: Value<u64>,
222///     b: Value<u64>,
223/// }
224///
225/// impl<F: PrimeField> Circuit<F> for MyCircuit {
226///     type Config = MyConfig;
227///     type FloorPlanner = SimpleFloorPlanner;
228///     #[cfg(feature = "circuit-params")]
229///     type Params = ();
230///
231///     fn without_witnesses(&self) -> Self {
232///         Self::default()
233///     }
234///
235///     fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
236///         let a = meta.advice_column();
237///         let b = meta.advice_column();
238///         let c = meta.advice_column();
239///         let s = meta.selector();
240///
241///         meta.create_gate("R1CS constraint", |meta| {
242///             let a = meta.query_advice(a, Rotation::cur());
243///             let b = meta.query_advice(b, Rotation::cur());
244///             let c = meta.query_advice(c, Rotation::cur());
245///             let s = meta.query_selector(s);
246///
247///             // BUG: Should be a * b - c
248///             Some(("buggy R1CS", s * (a * b + c)))
249///         });
250///
251///         MyConfig { a, b, c, s }
252///     }
253///
254///     fn synthesize(&self, config: MyConfig, mut layouter: impl Layouter<F>) -> Result<(), Error> {
255///         layouter.assign_region(|| "Example region", |mut region| {
256///             config.s.enable(&mut region, 0)?;
257///             region.assign_advice(config.a, 0, self.a.map(F::from));
258///             region.assign_advice(config.b, 0, self.b.map(F::from));
259///             region.assign_advice(config.c, 0, (self.a * self.b).map(F::from));
260///             Ok(())
261///         })
262///     }
263/// }
264///
265/// // Assemble the private inputs to the circuit.
266/// let circuit = MyCircuit {
267///     a: Value::known(2),
268///     b: Value::known(4),
269/// };
270///
271/// // This circuit has no public inputs.
272/// let instance = vec![];
273///
274/// let prover = MockProver::<Fp>::run(K, &circuit, instance).unwrap();
275/// assert_eq!(
276///     prover.verify(),
277///     Err(vec![VerifyFailure::ConstraintNotSatisfied {
278///         constraint: ((0, "R1CS constraint").into(), 0, "buggy R1CS").into(),
279///         location: FailureLocation::OutsideRegion { row: 0 },
280///         cell_values: vec![
281///             (((Any::advice(), 0).into(), 0).into(), "0x2".to_string()),
282///             (((Any::advice(), 1).into(), 0).into(), "0x4".to_string()),
283///             (((Any::advice(), 2).into(), 0).into(), "0x8".to_string()),
284///         ],
285///     }])
286/// );
287///
288/// // If we provide a too-small K, we get a panic.
289/// use std::panic;
290/// let result = panic::catch_unwind(|| {
291///     MockProver::<Fp>::run(2, &circuit, vec![]).unwrap_err()
292/// });
293/// assert_eq!(
294///     result.unwrap_err().downcast_ref::<String>().unwrap(),
295///     "n=4, minimum_rows=8, k=2"
296/// );
297/// ```
298#[derive(Debug)]
299pub struct MockProver<F: Field> {
300    k: u32,
301    n: u32,
302    cs: ConstraintSystem<F>,
303
304    /// The regions in the circuit.
305    regions: Vec<Region>,
306    /// The current region being assigned to. Will be `None` after the circuit has been
307    /// synthesized.
308    current_region: Option<Region>,
309
310    // The fixed cells in the circuit, arranged as [column][row].
311    fixed: Vec<Vec<CellValue<F>>>,
312    // The advice cells in the circuit, arranged as [column][row].
313    advice: Vec<Vec<AdviceCellValue<F>>>,
314    // The instance cells in the circuit, arranged as [column][row].
315    instance: Vec<Vec<InstanceValue<F>>>,
316
317    selectors: Vec<Vec<bool>>,
318
319    challenges: Vec<F>,
320
321    permutation: permutation::keygen::Assembly,
322
323    // A range of available rows for assignment and copies.
324    usable_rows: Range<usize>,
325
326    current_phase: sealed::Phase,
327}
328
329#[derive(Debug, Clone, PartialEq, Eq)]
330enum InstanceValue<F: Field> {
331    Assigned(F),
332    Padding,
333}
334
335impl<F: Field> InstanceValue<F> {
336    fn value(&self) -> F {
337        match self {
338            InstanceValue::Assigned(v) => *v,
339            InstanceValue::Padding => F::ZERO,
340        }
341    }
342}
343
344impl<F: Field> MockProver<F> {
345    fn in_phase<P: Phase>(&self, phase: P) -> bool {
346        self.current_phase == phase.to_sealed()
347    }
348}
349
350impl<F: Field> Assignment<F> for MockProver<F> {
351    fn enter_region<NR, N>(&mut self, name: N)
352    where
353        NR: Into<String>,
354        N: FnOnce() -> NR,
355    {
356        if !self.in_phase(FirstPhase) {
357            return;
358        }
359
360        assert!(self.current_region.is_none());
361        self.current_region = Some(Region {
362            name: name().into(),
363            columns: HashSet::default(),
364            rows: None,
365            annotations: HashMap::default(),
366            enabled_selectors: HashMap::default(),
367            cells: HashMap::default(),
368        });
369    }
370
371    fn exit_region(&mut self) {
372        if !self.in_phase(FirstPhase) {
373            return;
374        }
375
376        self.regions.push(self.current_region.take().unwrap());
377    }
378
379    fn annotate_column<A, AR>(&mut self, annotation: A, column: Column<Any>)
380    where
381        A: FnOnce() -> AR,
382        AR: Into<String>,
383    {
384        if !self.in_phase(FirstPhase) {
385            return;
386        }
387
388        if let Some(region) = self.current_region.as_mut() {
389            region
390                .annotations
391                .insert(ColumnMetadata::from(column), annotation().into());
392        }
393    }
394
395    fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
396    where
397        A: FnOnce() -> AR,
398        AR: Into<String>,
399    {
400        if !self.in_phase(FirstPhase) {
401            return Ok(());
402        }
403
404        assert!(
405            self.usable_rows.contains(&row),
406            "row={} not in usable_rows={:?}, k={}",
407            row,
408            self.usable_rows,
409            self.k,
410        );
411
412        // Track that this selector was enabled. We require that all selectors are enabled
413        // inside some region (i.e. no floating selectors).
414        self.current_region
415            .as_mut()
416            .unwrap()
417            .enabled_selectors
418            .entry(*selector)
419            .or_default()
420            .push(row);
421
422        self.selectors[selector.0][row] = true;
423
424        Ok(())
425    }
426
427    fn query_instance(
428        &self,
429        column: Column<Instance>,
430        row: usize,
431    ) -> Result<circuit::Value<F>, Error> {
432        assert!(
433            self.usable_rows.contains(&row),
434            "row={}, usable_rows={:?}, k={}",
435            row,
436            self.usable_rows,
437            self.k,
438        );
439
440        Ok(self
441            .instance
442            .get(column.index())
443            .and_then(|column| column.get(row))
444            .map(|v| circuit::Value::known(v.value()))
445            .expect("bound failure"))
446    }
447
448    fn assign_advice<'v>(
449        //<V, VR, A, AR>(
450        &mut self,
451        //_: A,
452        column: Column<Advice>,
453        row: usize,
454        to: circuit::Value<Assigned<F>>,
455    ) -> circuit::Value<&'v Assigned<F>> {
456        if self.in_phase(FirstPhase) {
457            assert!(
458                self.usable_rows.contains(&row),
459                "row={}, usable_rows={:?}, k={}",
460                row,
461                self.usable_rows,
462                self.k,
463            );
464        }
465
466        match to.assign() {
467            Ok(to) => {
468                let value = self
469                    .advice
470                    .get_mut(column.index())
471                    .and_then(|v| v.get_mut(row))
472                    .expect("bounds failure");
473                /* We don't use this because we do assign 0s in first pass of second phase sometimes
474                if let AdviceCellValue::Assigned(value) = value {
475                    // Inconsistent assignment between different phases.
476                    assert_eq!(value.as_ref(), &to, "value={:?}, to={:?}", &value, &to);
477                    let val = Arc::clone(&value);
478                    let val_ref = Arc::downgrade(&val);
479                    circuit::Value::known(unsafe { &*val_ref.as_ptr() })
480                } else {
481                */
482                let val = Arc::new(to);
483                let val_ref = Arc::downgrade(&val);
484                *value = AdviceCellValue::Assigned(val);
485                circuit::Value::known(unsafe { &*val_ref.as_ptr() })
486                //}
487            }
488            Err(err) => {
489                // Propagate `assign` error if the column is in current phase.
490                if self.in_phase(column.column_type().phase) {
491                    panic!("{:?}", err);
492                }
493                circuit::Value::unknown()
494            }
495        }
496    }
497
498    fn assign_fixed(&mut self, column: Column<Fixed>, row: usize, to: Assigned<F>) {
499        if !self.in_phase(FirstPhase) {
500            return;
501        }
502
503        assert!(
504            self.usable_rows.contains(&row),
505            "row={}, usable_rows={:?}, k={}",
506            row,
507            self.usable_rows,
508            self.k,
509        );
510
511        if let Some(region) = self.current_region.as_mut() {
512            region.update_extent(column.into(), row);
513            region
514                .cells
515                .entry((column.into(), row))
516                .and_modify(|count| *count += 1)
517                .or_default();
518        }
519
520        *self
521            .fixed
522            .get_mut(column.index())
523            .and_then(|v| v.get_mut(row))
524            .expect("bounds failure") = CellValue::Assigned(to.evaluate());
525    }
526
527    fn copy(
528        &mut self,
529        left_column: Column<Any>,
530        left_row: usize,
531        right_column: Column<Any>,
532        right_row: usize,
533    ) {
534        if !self.in_phase(FirstPhase) {
535            return;
536        }
537
538        assert!(
539            self.usable_rows.contains(&left_row) && self.usable_rows.contains(&right_row),
540            "left_row={}, right_row={}, usable_rows={:?}, k={}",
541            left_row,
542            right_row,
543            self.usable_rows,
544            self.k,
545        );
546
547        self.permutation
548            .copy(left_column, left_row, right_column, right_row)
549            .unwrap_or_else(|err| panic!("{err:?}"))
550    }
551
552    fn fill_from_row(
553        &mut self,
554        col: Column<Fixed>,
555        from_row: usize,
556        to: circuit::Value<Assigned<F>>,
557    ) -> Result<(), Error> {
558        if !self.in_phase(FirstPhase) {
559            return Ok(());
560        }
561
562        assert!(
563            self.usable_rows.contains(&from_row),
564            "row={}, usable_rows={:?}, k={}",
565            from_row,
566            self.usable_rows,
567            self.k,
568        );
569
570        for row in self.usable_rows.clone().skip(from_row) {
571            self.assign_fixed(col, row, to.assign()?);
572        }
573
574        Ok(())
575    }
576
577    fn get_challenge(&self, challenge: Challenge) -> circuit::Value<F> {
578        if self.current_phase <= challenge.phase {
579            return circuit::Value::unknown();
580        }
581
582        circuit::Value::known(self.challenges[challenge.index()])
583    }
584
585    fn push_namespace<NR, N>(&mut self, _: N)
586    where
587        NR: Into<String>,
588        N: FnOnce() -> NR,
589    {
590        // TODO: Do something with namespaces :)
591    }
592
593    fn pop_namespace(&mut self, _: Option<String>) {
594        // TODO: Do something with namespaces :)
595    }
596}
597
598impl<F: FromUniformBytes<64> + Ord> MockProver<F> {
599    /// Runs a synthetic keygen-and-prove operation on the given circuit, collecting data
600    /// about the constraints and their assignments.
601    pub fn run<ConcreteCircuit: Circuit<F>>(
602        k: u32,
603        circuit: &ConcreteCircuit,
604        instance: Vec<Vec<F>>,
605    ) -> Result<Self, Error> {
606        let n = 1 << k;
607
608        let mut cs = ConstraintSystem::default();
609        #[cfg(feature = "circuit-params")]
610        let config = ConcreteCircuit::configure_with_params(&mut cs, circuit.params());
611        #[cfg(not(feature = "circuit-params"))]
612        let config = ConcreteCircuit::configure(&mut cs);
613        let cs = cs;
614
615        assert!(
616            n >= cs.minimum_rows(),
617            "n={}, minimum_rows={}, k={}",
618            n,
619            cs.minimum_rows(),
620            k,
621        );
622
623        assert_eq!(instance.len(), cs.num_instance_columns);
624
625        let instance = instance
626            .into_iter()
627            .map(|instance| {
628                assert!(
629                    instance.len() <= n - (cs.blinding_factors() + 1),
630                    "instance.len={}, n={}, cs.blinding_factors={}",
631                    instance.len(),
632                    n,
633                    cs.blinding_factors()
634                );
635
636                let mut instance_values = vec![InstanceValue::Padding; n];
637                for (idx, value) in instance.into_iter().enumerate() {
638                    instance_values[idx] = InstanceValue::Assigned(value);
639                }
640
641                instance_values
642            })
643            .collect::<Vec<_>>();
644
645        // Fixed columns contain no blinding factors.
646        let fixed = vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns];
647        let selectors = vec![vec![false; n]; cs.num_selectors];
648        // Advice columns contain blinding factors.
649        let blinding_factors = cs.blinding_factors();
650        let usable_rows = n - (blinding_factors + 1);
651        let advice = vec![
652            {
653                // let mut column = vec![AdviceCellValue::Unassigned; n];
654                // Assign advice to 0 by default so we can have gates that query unassigned rotations to minimize number of distinct rotation sets, for SHPLONK optimization
655                let mut column =
656                    vec![AdviceCellValue::Assigned(Arc::new(Assigned::Trivial(F::ZERO))); n];
657                // Poison unusable rows.
658                for (i, cell) in column.iter_mut().enumerate().skip(usable_rows) {
659                    *cell = AdviceCellValue::Poison(i);
660                }
661                column
662            };
663            cs.num_advice_columns
664        ];
665        let permutation = permutation::keygen::Assembly::new(n, &cs.permutation);
666        let constants = cs.constants.clone();
667
668        // Use hash chain to derive deterministic challenges for testing
669        let challenges = {
670            let mut hash: [u8; 64] = blake2b(b"Halo2-MockProver").as_bytes().try_into().unwrap();
671            iter::repeat_with(|| {
672                hash = blake2b(&hash).as_bytes().try_into().unwrap();
673                F::from_uniform_bytes(&hash)
674            })
675            .take(cs.num_challenges)
676            .collect()
677        };
678
679        let mut prover = MockProver {
680            k,
681            n: n as u32,
682            cs,
683            regions: vec![],
684            current_region: None,
685            fixed,
686            advice,
687            instance,
688            selectors,
689            challenges,
690            permutation,
691            usable_rows: 0..usable_rows,
692            current_phase: FirstPhase.to_sealed(),
693        };
694
695        for current_phase in prover.cs.phases() {
696            prover.current_phase = current_phase;
697            ConcreteCircuit::FloorPlanner::synthesize(
698                &mut prover,
699                circuit,
700                config.clone(),
701                constants.clone(),
702            )?;
703        }
704
705        let (cs, selector_polys) = prover.cs.compress_selectors(prover.selectors.clone());
706        prover.cs = cs;
707        prover.fixed.extend(selector_polys.into_iter().map(|poly| {
708            let mut v = vec![CellValue::Unassigned; n];
709            for (v, p) in v.iter_mut().zip(&poly[..]) {
710                *v = CellValue::Assigned(*p);
711            }
712            v
713        }));
714
715        #[cfg(feature = "thread-safe-region")]
716        prover.permutation.build_ordered_mapping();
717
718        Ok(prover)
719    }
720
721    /// Return the content of an advice column as assigned by the circuit.
722    pub fn advice_values(&self, column: Column<Advice>) -> &[AdviceCellValue<F>] {
723        &self.advice[column.index()]
724    }
725
726    /// Return the content of a fixed column as assigned by the circuit.
727    pub fn fixed_values(&self, column: Column<Fixed>) -> &[CellValue<F>] {
728        &self.fixed[column.index()]
729    }
730
731    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
732    /// the reasons that the circuit is not satisfied.
733    pub fn verify(&self) -> Result<(), Vec<VerifyFailure>> {
734        self.verify_at_rows(self.usable_rows.clone(), self.usable_rows.clone())
735    }
736
737    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
738    /// the reasons that the circuit is not satisfied.
739    /// Constraints are only checked at `gate_row_ids`,
740    /// and lookup inputs are only checked at `lookup_input_row_ids`
741    pub fn verify_at_rows<I: Clone + Iterator<Item = usize>>(
742        &self,
743        gate_row_ids: I,
744        lookup_input_row_ids: I,
745    ) -> Result<(), Vec<VerifyFailure>> {
746        let n = self.n as i32;
747
748        // check all the row ids are valid
749        for row_id in gate_row_ids.clone() {
750            if !self.usable_rows.contains(&row_id) {
751                panic!("invalid gate row id {}", row_id)
752            }
753        }
754        for row_id in lookup_input_row_ids.clone() {
755            if !self.usable_rows.contains(&row_id) {
756                panic!("invalid lookup row id {}", row_id)
757            }
758        }
759
760        // Check that within each region, all cells used in instantiated gates have been
761        // assigned to.
762
763        // Turn off this check because we might query unassigned cells to increase the rotation set size of a gate (for SHPLONK optimization)
764        /*
765        let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| {
766            r.enabled_selectors.iter().flat_map(move |(selector, at)| {
767                // Find the gates enabled by this selector
768                self.cs
769                    .gates
770                    .iter()
771                    // Assume that if a queried selector is enabled, the user wants to use the
772                    // corresponding gate in some way.
773                    //
774                    // TODO: This will trip up on the reverse case, where leaving a selector
775                    // un-enabled keeps a gate enabled. We could alternatively require that
776                    // every selector is explicitly enabled or disabled on every row? But that
777                    // seems messy and confusing.
778                    .enumerate()
779                    .filter(move |(_, g)| g.queried_selectors().contains(selector))
780                    .flat_map(move |(gate_index, gate)| {
781                        at.iter().flat_map(move |selector_row| {
782                            // Selectors are queried with no rotation.
783                            let gate_row = *selector_row as i32;
784
785                            gate.queried_cells().iter().filter_map(move |cell| {
786                                // Determine where this cell should have been assigned.
787                                let cell_row = ((gate_row + n + cell.rotation.0) % n) as usize;
788
789                                match cell.column.column_type() {
790                                    Any::Instance => {
791                                        // Handle instance cells, which are not in the region.
792                                        let instance_value =
793                                            &self.instance[cell.column.index()][cell_row];
794                                        match instance_value {
795                                            InstanceValue::Assigned(_) => None,
796                                            _ => Some(VerifyFailure::InstanceCellNotAssigned {
797                                                gate: (gate_index, gate.name()).into(),
798                                                region: (r_i, r.name.clone()).into(),
799                                                gate_offset: *selector_row,
800                                                column: cell.column.try_into().unwrap(),
801                                                row: cell_row,
802                                            }),
803                                        }
804                                    }
805                                    _ => {
806                                        // Check that it was assigned!
807                                        if r.cells.contains_key(&(cell.column, cell_row)) {
808                                            None
809                                        } else {
810                                            Some(VerifyFailure::CellNotAssigned {
811                                                gate: (gate_index, gate.name()).into(),
812                                                region: (
813                                                    r_i,
814                                                    r.name.clone(),
815                                                    r.annotations.clone(),
816                                                )
817                                                    .into(),
818                                                gate_offset: *selector_row,
819                                                column: cell.column,
820                                                offset: cell_row as isize
821                                                    - r.rows.unwrap().0 as isize,
822                                            })
823                                        }
824                                    }
825                                }
826                            })
827                        })
828                    })
829            })
830        });
831        */
832
833        let advice = self
834            .advice
835            .iter()
836            .map(|advice| {
837                advice
838                    .iter()
839                    .map(|rc| match *rc {
840                        AdviceCellValue::Assigned(ref a) => CellValue::Assigned(match a.as_ref() {
841                            Assigned::Trivial(a) => *a,
842                            Assigned::Rational(a, b) => *a * b.invert().unwrap(),
843                            _ => F::ZERO,
844                        }),
845                        AdviceCellValue::Poison(i) => CellValue::Poison(i),
846                    })
847                    .collect::<Vec<_>>()
848            })
849            .collect::<Vec<_>>();
850        let advice = &advice;
851        // Check that all gates are satisfied for all rows.
852        let gate_errors =
853            self.cs
854                .gates
855                .iter()
856                .enumerate()
857                .flat_map(|(gate_index, gate)| {
858                    let blinding_rows =
859                        (self.n as usize - (self.cs.blinding_factors() + 1))..(self.n as usize);
860                    (gate_row_ids.clone().chain(blinding_rows)).flat_map(move |row| {
861                        let row = row as i32 + n;
862                        gate.polynomials().iter().enumerate().filter_map(
863                            move |(poly_index, poly)| match poly.evaluate_lazy(
864                                &|scalar| Value::Real(scalar),
865                                &|_| panic!("virtual selectors are removed during optimization"),
866                                &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
867                                &util::load(n, row, &self.cs.advice_queries, advice),
868                                &util::load_instance(
869                                    n,
870                                    row,
871                                    &self.cs.instance_queries,
872                                    &self.instance,
873                                ),
874                                &|challenge| Value::Real(self.challenges[challenge.index()]),
875                                &|a| -a,
876                                &|a, b| a + b,
877                                &|a, b| a * b,
878                                &|a, scalar| a * scalar,
879                                &Value::Real(F::ZERO),
880                            ) {
881                                Value::Real(x) if x.is_zero_vartime() => None,
882                                Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied {
883                                    constraint: (
884                                        (gate_index, gate.name()).into(),
885                                        poly_index,
886                                        gate.constraint_name(poly_index),
887                                    )
888                                        .into(),
889                                    location: FailureLocation::find_expressions(
890                                        &self.cs,
891                                        &self.regions,
892                                        (row - n) as usize,
893                                        Some(poly).into_iter(),
894                                    ),
895                                    cell_values: util::cell_values(
896                                        gate,
897                                        poly,
898                                        &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
899                                        &util::load(n, row, &self.cs.advice_queries, advice),
900                                        &util::load_instance(
901                                            n,
902                                            row,
903                                            &self.cs.instance_queries,
904                                            &self.instance,
905                                        ),
906                                    ),
907                                }),
908                                Value::Poison => Some(VerifyFailure::ConstraintPoisoned {
909                                    constraint: (
910                                        (gate_index, gate.name()).into(),
911                                        poly_index,
912                                        gate.constraint_name(poly_index),
913                                    )
914                                        .into(),
915                                }),
916                            },
917                        )
918                    })
919                });
920
921        let load = |expression: &Expression<F>, row| {
922            expression.evaluate_lazy(
923                &|scalar| Value::Real(scalar),
924                &|_| panic!("virtual selectors are removed during optimization"),
925                &|query| {
926                    let query = self.cs.fixed_queries[query.index.unwrap()];
927                    let column_index = query.0.index();
928                    let rotation = query.1 .0;
929                    self.fixed[column_index][(row as i32 + n + rotation) as usize % n as usize]
930                        .into()
931                },
932                &|query| {
933                    let query = self.cs.advice_queries[query.index.unwrap()];
934                    let column_index = query.0.index();
935                    let rotation = query.1 .0;
936                    self.advice[column_index][(row as i32 + n + rotation) as usize % n as usize]
937                        .clone()
938                        .into()
939                },
940                &|query| {
941                    let query = self.cs.instance_queries[query.index.unwrap()];
942                    let column_index = query.0.index();
943                    let rotation = query.1 .0;
944                    Value::Real(
945                        self.instance[column_index]
946                            [(row as i32 + n + rotation) as usize % n as usize]
947                            .value(),
948                    )
949                },
950                &|challenge| Value::Real(self.challenges[challenge.index()]),
951                &|a| -a,
952                &|a, b| a + b,
953                &|a, b| a * b,
954                &|a, scalar| a * scalar,
955                &Value::Real(F::ZERO),
956            )
957        };
958
959        let mut cached_table = Vec::new();
960        let mut cached_table_identifier = Vec::new();
961        // Check that all lookups exist in their respective tables.
962        let lookup_errors =
963            self.cs
964                .lookups
965                .iter()
966                .enumerate()
967                .flat_map(|(lookup_index, lookup)| {
968                    assert!(lookup.table_expressions.len() == lookup.input_expressions.len());
969                    assert!(self.usable_rows.end > 0);
970
971                    // We optimize on the basis that the table might have been filled so that the last
972                    // usable row now has the fill contents (it doesn't matter if there was no filling).
973                    // Note that this "fill row" necessarily exists in the table, and we use that fact to
974                    // slightly simplify the optimization: we're only trying to check that all input rows
975                    // are contained in the table, and so we can safely just drop input rows that
976                    // match the fill row.
977                    let fill_row: Vec<_> = lookup
978                        .table_expressions
979                        .iter()
980                        .map(move |c| load(c, self.usable_rows.end - 1))
981                        .collect();
982
983                    let table_identifier = lookup
984                        .table_expressions
985                        .iter()
986                        .map(Expression::identifier)
987                        .collect::<Vec<_>>();
988                    if table_identifier != cached_table_identifier {
989                        cached_table_identifier = table_identifier;
990
991                        // In the real prover, the lookup expressions are never enforced on
992                        // unusable rows, due to the (1 - (l_last(X) + l_blind(X))) term.
993                        cached_table = self
994                            .usable_rows
995                            .clone()
996                            .filter_map(|table_row| {
997                                let t = lookup
998                                    .table_expressions
999                                    .iter()
1000                                    .map(move |c| load(c, table_row))
1001                                    .collect();
1002
1003                                if t != fill_row {
1004                                    Some(t)
1005                                } else {
1006                                    None
1007                                }
1008                            })
1009                            .collect();
1010                        cached_table.sort_unstable();
1011                    }
1012                    let table = &cached_table;
1013
1014                    let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids
1015                        .clone()
1016                        .filter_map(|input_row| {
1017                            let t = lookup
1018                                .input_expressions
1019                                .iter()
1020                                .map(move |c| load(c, input_row))
1021                                .collect();
1022
1023                            if t != fill_row {
1024                                // Also keep track of the original input row, since we're going to sort.
1025                                Some((t, input_row))
1026                            } else {
1027                                None
1028                            }
1029                        })
1030                        .collect();
1031                    inputs.sort_unstable();
1032
1033                    let mut i = 0;
1034                    inputs
1035                        .iter()
1036                        .filter_map(move |(input, input_row)| {
1037                            while i < table.len() && &table[i] < input {
1038                                i += 1;
1039                            }
1040                            if i == table.len() || &table[i] > input {
1041                                assert!(table.binary_search(input).is_err());
1042
1043                                Some(VerifyFailure::Lookup {
1044                                    name: lookup.name.clone(),
1045                                    lookup_index,
1046                                    location: FailureLocation::find_expressions(
1047                                        &self.cs,
1048                                        &self.regions,
1049                                        *input_row,
1050                                        lookup.input_expressions.iter(),
1051                                    ),
1052                                })
1053                            } else {
1054                                None
1055                            }
1056                        })
1057                        .collect::<Vec<_>>()
1058                });
1059
1060        let mapping = self.permutation.mapping();
1061        // Check that permutations preserve the original values of the cells.
1062        let perm_errors = {
1063            // Original values of columns involved in the permutation.
1064            let original = |column, row| {
1065                self.cs
1066                    .permutation
1067                    .get_columns()
1068                    .get(column)
1069                    .map(|c: &Column<Any>| match c.column_type() {
1070                        Any::Advice(_) => advice[c.index()][row],
1071                        Any::Fixed => self.fixed[c.index()][row],
1072                        Any::Instance => {
1073                            let cell: &InstanceValue<F> = &self.instance[c.index()][row];
1074                            CellValue::Assigned(cell.value())
1075                        }
1076                    })
1077                    .unwrap()
1078            };
1079
1080            // Iterate over each column of the permutation
1081            mapping.enumerate().flat_map(move |(column, values)| {
1082                // Iterate over each row of the column to check that the cell's
1083                // value is preserved by the mapping.
1084                values
1085                    .enumerate()
1086                    .filter_map(move |(row, cell)| {
1087                        let original_cell = original(column, row);
1088                        let permuted_cell = original(cell.0, cell.1);
1089                        if original_cell == permuted_cell {
1090                            None
1091                        } else {
1092                            let columns = self.cs.permutation.get_columns();
1093                            let column = columns.get(column).unwrap();
1094                            Some(VerifyFailure::Permutation {
1095                                column: (*column).into(),
1096                                location: FailureLocation::find(
1097                                    &self.regions,
1098                                    row,
1099                                    Some(column).into_iter().cloned().collect(),
1100                                ),
1101                            })
1102                        }
1103                    })
1104                    .collect::<Vec<_>>()
1105            })
1106        };
1107
1108        let mut errors: Vec<_> = iter::empty()
1109            //.chain(selector_errors)
1110            .chain(gate_errors)
1111            .chain(lookup_errors)
1112            .chain(perm_errors)
1113            .collect();
1114        if errors.is_empty() {
1115            Ok(())
1116        } else {
1117            // Remove any duplicate `ConstraintPoisoned` errors (we check all unavailable
1118            // rows in case the trigger is row-specific, but the error message only points
1119            // at the constraint).
1120            errors.dedup_by(|a, b| match (a, b) {
1121                (
1122                    a @ VerifyFailure::ConstraintPoisoned { .. },
1123                    b @ VerifyFailure::ConstraintPoisoned { .. },
1124                ) => a == b,
1125                _ => false,
1126            });
1127            Err(errors)
1128        }
1129    }
1130
1131    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
1132    /// the reasons that the circuit is not satisfied.
1133    /// Constraints and lookup are checked at `usable_rows`, parallelly.
1134    #[cfg(feature = "multicore")]
1135    pub fn verify_par(&self) -> Result<(), Vec<VerifyFailure>> {
1136        self.verify_at_rows_par(self.usable_rows.clone(), self.usable_rows.clone())
1137    }
1138
1139    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
1140    /// the reasons that the circuit is not satisfied.
1141    /// Constraints are only checked at `gate_row_ids`, and lookup inputs are only checked at `lookup_input_row_ids`, parallelly.
1142    #[cfg(feature = "multicore")]
1143    pub fn verify_at_rows_par<I: Clone + Iterator<Item = usize>>(
1144        &self,
1145        gate_row_ids: I,
1146        lookup_input_row_ids: I,
1147    ) -> Result<(), Vec<VerifyFailure>> {
1148        let n = self.n as i32;
1149
1150        let gate_row_ids = gate_row_ids.collect::<Vec<_>>();
1151        let lookup_input_row_ids = lookup_input_row_ids.collect::<Vec<_>>();
1152
1153        // check all the row ids are valid
1154        gate_row_ids.par_iter().for_each(|row_id| {
1155            if !self.usable_rows.contains(row_id) {
1156                panic!("invalid gate row id {}", row_id);
1157            }
1158        });
1159        lookup_input_row_ids.par_iter().for_each(|row_id| {
1160            if !self.usable_rows.contains(row_id) {
1161                panic!("invalid gate row id {}", row_id);
1162            }
1163        });
1164
1165        // Check that within each region, all cells used in instantiated gates have been
1166        // assigned to.
1167        let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| {
1168            r.enabled_selectors.iter().flat_map(move |(selector, at)| {
1169                // Find the gates enabled by this selector
1170                self.cs
1171                    .gates
1172                    .iter()
1173                    // Assume that if a queried selector is enabled, the user wants to use the
1174                    // corresponding gate in some way.
1175                    //
1176                    // TODO: This will trip up on the reverse case, where leaving a selector
1177                    // un-enabled keeps a gate enabled. We could alternatively require that
1178                    // every selector is explicitly enabled or disabled on every row? But that
1179                    // seems messy and confusing.
1180                    .enumerate()
1181                    .filter(move |(_, g)| g.queried_selectors().contains(selector))
1182                    .flat_map(move |(gate_index, gate)| {
1183                        at.par_iter()
1184                            .flat_map(move |selector_row| {
1185                                // Selectors are queried with no rotation.
1186                                let gate_row = *selector_row as i32;
1187
1188                                gate.queried_cells()
1189                                    .iter()
1190                                    .filter_map(move |cell| {
1191                                        // Determine where this cell should have been assigned.
1192                                        let cell_row =
1193                                            ((gate_row + n + cell.rotation.0) % n) as usize;
1194
1195                                        match cell.column.column_type() {
1196                                            Any::Instance => {
1197                                                // Handle instance cells, which are not in the region.
1198                                                let instance_value =
1199                                                    &self.instance[cell.column.index()][cell_row];
1200                                                match instance_value {
1201                                                    InstanceValue::Assigned(_) => None,
1202                                                    _ => Some(
1203                                                        VerifyFailure::InstanceCellNotAssigned {
1204                                                            gate: (gate_index, gate.name()).into(),
1205                                                            region: (r_i, r.name.clone()).into(),
1206                                                            gate_offset: *selector_row,
1207                                                            column: cell.column.try_into().unwrap(),
1208                                                            row: cell_row,
1209                                                        },
1210                                                    ),
1211                                                }
1212                                            }
1213                                            _ => {
1214                                                // Check that it was assigned!
1215                                                if r.cells.contains_key(&(cell.column, cell_row)) {
1216                                                    None
1217                                                } else {
1218                                                    Some(VerifyFailure::CellNotAssigned {
1219                                                        gate: (gate_index, gate.name()).into(),
1220                                                        region: (
1221                                                            r_i,
1222                                                            r.name.clone(),
1223                                                            r.annotations.clone(),
1224                                                        )
1225                                                            .into(),
1226                                                        gate_offset: *selector_row,
1227                                                        column: cell.column,
1228                                                        offset: cell_row as isize
1229                                                            - r.rows.unwrap().0 as isize,
1230                                                    })
1231                                                }
1232                                            }
1233                                        }
1234                                    })
1235                                    .collect::<Vec<_>>()
1236                            })
1237                            .collect::<Vec<_>>()
1238                    })
1239            })
1240        });
1241
1242        let advice = self
1243            .advice
1244            .iter()
1245            .map(|advice| {
1246                advice
1247                    .iter()
1248                    .map(|rc| match *rc {
1249                        AdviceCellValue::Assigned(ref a) => CellValue::Assigned(a.evaluate()),
1250                        AdviceCellValue::Poison(i) => CellValue::Poison(i),
1251                    })
1252                    .collect::<Vec<_>>()
1253            })
1254            .collect::<Vec<_>>();
1255        let advice = &advice;
1256        // Check that all gates are satisfied for all rows.
1257        let gate_errors = self
1258            .cs
1259            .gates
1260            .iter()
1261            .enumerate()
1262            .flat_map(|(gate_index, gate)| {
1263                let blinding_rows =
1264                    (self.n as usize - (self.cs.blinding_factors() + 1))..(self.n as usize);
1265                (gate_row_ids
1266                    .clone()
1267                    .into_par_iter()
1268                    .chain(blinding_rows.into_par_iter()))
1269                .flat_map(move |row| {
1270                    let row = row as i32 + n;
1271                    gate.polynomials()
1272                        .iter()
1273                        .enumerate()
1274                        .filter_map(move |(poly_index, poly)| {
1275                            match poly.evaluate_lazy(
1276                                &|scalar| Value::Real(scalar),
1277                                &|_| panic!("virtual selectors are removed during optimization"),
1278                                &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
1279                                &util::load(n, row, &self.cs.advice_queries, advice),
1280                                &util::load_instance(
1281                                    n,
1282                                    row,
1283                                    &self.cs.instance_queries,
1284                                    &self.instance,
1285                                ),
1286                                &|challenge| Value::Real(self.challenges[challenge.index()]),
1287                                &|a| -a,
1288                                &|a, b| a + b,
1289                                &|a, b| a * b,
1290                                &|a, scalar| a * scalar,
1291                                &Value::Real(F::ZERO),
1292                            ) {
1293                                Value::Real(x) if x.is_zero_vartime() => None,
1294                                Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied {
1295                                    constraint: (
1296                                        (gate_index, gate.name()).into(),
1297                                        poly_index,
1298                                        gate.constraint_name(poly_index),
1299                                    )
1300                                        .into(),
1301                                    location: FailureLocation::find_expressions(
1302                                        &self.cs,
1303                                        &self.regions,
1304                                        (row - n) as usize,
1305                                        Some(poly).into_iter(),
1306                                    ),
1307                                    cell_values: util::cell_values(
1308                                        gate,
1309                                        poly,
1310                                        &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
1311                                        &util::load(n, row, &self.cs.advice_queries, advice),
1312                                        &util::load_instance(
1313                                            n,
1314                                            row,
1315                                            &self.cs.instance_queries,
1316                                            &self.instance,
1317                                        ),
1318                                    ),
1319                                }),
1320                                Value::Poison => Some(VerifyFailure::ConstraintPoisoned {
1321                                    constraint: (
1322                                        (gate_index, gate.name()).into(),
1323                                        poly_index,
1324                                        gate.constraint_name(poly_index),
1325                                    )
1326                                        .into(),
1327                                }),
1328                            }
1329                        })
1330                        .collect::<Vec<_>>()
1331                })
1332                .collect::<Vec<_>>()
1333            });
1334
1335        let load = |expression: &Expression<F>, row| {
1336            expression.evaluate_lazy(
1337                &|scalar| Value::Real(scalar),
1338                &|_| panic!("virtual selectors are removed during optimization"),
1339                &|query| {
1340                    self.fixed[query.column_index]
1341                        [(row as i32 + n + query.rotation.0) as usize % n as usize]
1342                        .into()
1343                },
1344                &|query| {
1345                    self.advice[query.column_index]
1346                        [(row as i32 + n + query.rotation.0) as usize % n as usize]
1347                        .clone()
1348                        .into()
1349                },
1350                &|query| {
1351                    Value::Real(
1352                        self.instance[query.column_index]
1353                            [(row as i32 + n + query.rotation.0) as usize % n as usize]
1354                            .value(),
1355                    )
1356                },
1357                &|challenge| Value::Real(self.challenges[challenge.index()]),
1358                &|a| -a,
1359                &|a, b| a + b,
1360                &|a, b| a * b,
1361                &|a, scalar| a * scalar,
1362                &Value::Real(F::ZERO),
1363            )
1364        };
1365
1366        let mut cached_table = Vec::new();
1367        let mut cached_table_identifier = Vec::new();
1368        // Check that all lookups exist in their respective tables.
1369        let lookup_errors =
1370            self.cs
1371                .lookups
1372                .iter()
1373                .enumerate()
1374                .flat_map(|(lookup_index, lookup)| {
1375                    assert!(lookup.table_expressions.len() == lookup.input_expressions.len());
1376                    assert!(self.usable_rows.end > 0);
1377
1378                    // We optimize on the basis that the table might have been filled so that the last
1379                    // usable row now has the fill contents (it doesn't matter if there was no filling).
1380                    // Note that this "fill row" necessarily exists in the table, and we use that fact to
1381                    // slightly simplify the optimization: we're only trying to check that all input rows
1382                    // are contained in the table, and so we can safely just drop input rows that
1383                    // match the fill row.
1384                    let fill_row: Vec<_> = lookup
1385                        .table_expressions
1386                        .iter()
1387                        .map(move |c| load(c, self.usable_rows.end - 1))
1388                        .collect();
1389
1390                    let table_identifier = lookup
1391                        .table_expressions
1392                        .iter()
1393                        .map(Expression::identifier)
1394                        .collect::<Vec<_>>();
1395                    if table_identifier != cached_table_identifier {
1396                        cached_table_identifier = table_identifier;
1397
1398                        // In the real prover, the lookup expressions are never enforced on
1399                        // unusable rows, due to the (1 - (l_last(X) + l_blind(X))) term.
1400                        cached_table = self
1401                            .usable_rows
1402                            .clone()
1403                            .into_par_iter()
1404                            .filter_map(|table_row| {
1405                                let t = lookup
1406                                    .table_expressions
1407                                    .iter()
1408                                    .map(move |c| load(c, table_row))
1409                                    .collect();
1410
1411                                if t != fill_row {
1412                                    Some(t)
1413                                } else {
1414                                    None
1415                                }
1416                            })
1417                            .collect();
1418                        cached_table.par_sort_unstable();
1419                    }
1420                    let table = &cached_table;
1421
1422                    let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids
1423                        .clone()
1424                        .into_par_iter()
1425                        .filter_map(|input_row| {
1426                            let t = lookup
1427                                .input_expressions
1428                                .iter()
1429                                .map(move |c| load(c, input_row))
1430                                .collect();
1431
1432                            if t != fill_row {
1433                                // Also keep track of the original input row, since we're going to sort.
1434                                Some((t, input_row))
1435                            } else {
1436                                None
1437                            }
1438                        })
1439                        .collect();
1440                    inputs.par_sort_unstable();
1441
1442                    inputs
1443                        .par_iter()
1444                        .filter_map(move |(input, input_row)| {
1445                            if table.binary_search(input).is_err() {
1446                                Some(VerifyFailure::Lookup {
1447                                    name: lookup.name.clone(),
1448                                    lookup_index,
1449                                    location: FailureLocation::find_expressions(
1450                                        &self.cs,
1451                                        &self.regions,
1452                                        *input_row,
1453                                        lookup.input_expressions.iter(),
1454                                    ),
1455                                })
1456                            } else {
1457                                None
1458                            }
1459                        })
1460                        .collect::<Vec<_>>()
1461                });
1462
1463        let mapping = self.permutation.mapping();
1464        // Check that permutations preserve the original values of the cells.
1465        let perm_errors = {
1466            // Original values of columns involved in the permutation.
1467            let original = |column, row| {
1468                self.cs
1469                    .permutation
1470                    .get_columns()
1471                    .get(column)
1472                    .map(|c: &Column<Any>| match c.column_type() {
1473                        Any::Advice(_) => advice[c.index()][row],
1474                        Any::Fixed => self.fixed[c.index()][row],
1475                        Any::Instance => {
1476                            let cell: &InstanceValue<F> = &self.instance[c.index()][row];
1477                            CellValue::Assigned(cell.value())
1478                        }
1479                    })
1480                    .unwrap()
1481            };
1482
1483            // Iterate over each column of the permutation
1484            mapping.enumerate().flat_map(move |(column, values)| {
1485                // Iterate over each row of the column to check that the cell's
1486                // value is preserved by the mapping.
1487                values
1488                    .enumerate()
1489                    .filter_map(move |(row, cell)| {
1490                        let original_cell = original(column, row);
1491                        let permuted_cell = original(cell.0, cell.1);
1492                        if original_cell == permuted_cell {
1493                            None
1494                        } else {
1495                            let columns = self.cs.permutation.get_columns();
1496                            let column = columns.get(column).unwrap();
1497                            Some(VerifyFailure::Permutation {
1498                                column: (*column).into(),
1499                                location: FailureLocation::find(
1500                                    &self.regions,
1501                                    row,
1502                                    Some(column).into_iter().cloned().collect(),
1503                                ),
1504                            })
1505                        }
1506                    })
1507                    .collect::<Vec<_>>()
1508            })
1509        };
1510
1511        let mut errors: Vec<_> = iter::empty()
1512            .chain(selector_errors)
1513            .chain(gate_errors)
1514            .chain(lookup_errors)
1515            .chain(perm_errors)
1516            .collect();
1517        if errors.is_empty() {
1518            Ok(())
1519        } else {
1520            // Remove any duplicate `ConstraintPoisoned` errors (we check all unavailable
1521            // rows in case the trigger is row-specific, but the error message only points
1522            // at the constraint).
1523            errors.dedup_by(|a, b| match (a, b) {
1524                (
1525                    a @ VerifyFailure::ConstraintPoisoned { .. },
1526                    b @ VerifyFailure::ConstraintPoisoned { .. },
1527                ) => a == b,
1528                _ => false,
1529            });
1530            Err(errors)
1531        }
1532    }
1533
1534    /// Panics if the circuit being checked by this `MockProver` is not satisfied.
1535    ///
1536    /// Any verification failures will be pretty-printed to stderr before the function
1537    /// panics.
1538    ///
1539    /// Apart from the stderr output, this method is equivalent to:
1540    /// ```ignore
1541    /// assert_eq!(prover.verify(), Ok(()));
1542    /// ```
1543    pub fn assert_satisfied(&self) {
1544        if let Err(errs) = self.verify() {
1545            for err in errs {
1546                err.emit(self);
1547                eprintln!();
1548            }
1549            panic!("circuit was not satisfied");
1550        }
1551    }
1552
1553    /// Panics if the circuit being checked by this `MockProver` is not satisfied.
1554    ///
1555    /// Any verification failures will be pretty-printed to stderr before the function
1556    /// panics.
1557    ///
1558    /// Internally, this function uses a parallel aproach in order to verify the `MockProver` contents.
1559    ///
1560    /// Apart from the stderr output, this method is equivalent to:
1561    /// ```ignore
1562    /// assert_eq!(prover.verify_par(), Ok(()));
1563    /// ```
1564    #[cfg(feature = "multicore")]
1565    pub fn assert_satisfied_par(&self) {
1566        if let Err(errs) = self.verify_par() {
1567            for err in errs {
1568                err.emit(self);
1569                eprintln!();
1570            }
1571            panic!("circuit was not satisfied");
1572        }
1573    }
1574
1575    /// Panics if the circuit being checked by this `MockProver` is not satisfied.
1576    ///
1577    /// Any verification failures will be pretty-printed to stderr before the function
1578    /// panics.
1579    ///
1580    /// Constraints are only checked at `gate_row_ids`, and lookup inputs are only checked at `lookup_input_row_ids`, parallelly.
1581    ///
1582    /// Apart from the stderr output, this method is equivalent to:
1583    /// ```ignore
1584    /// assert_eq!(prover.verify_at_rows_par(), Ok(()));
1585    /// ```
1586    #[cfg(feature = "multicore")]
1587    pub fn assert_satisfied_at_rows_par<I: Clone + Iterator<Item = usize>>(
1588        &self,
1589        gate_row_ids: I,
1590        lookup_input_row_ids: I,
1591    ) {
1592        if let Err(errs) = self.verify_at_rows_par(gate_row_ids, lookup_input_row_ids) {
1593            for err in errs {
1594                err.emit(self);
1595                eprintln!();
1596            }
1597            panic!("circuit was not satisfied");
1598        }
1599    }
1600
1601    /// Returns the list of Fixed Columns used within a MockProver instance and the associated values contained on each Cell.
1602    pub fn fixed(&self) -> &Vec<Vec<CellValue<F>>> {
1603        &self.fixed
1604    }
1605
1606    /// Returns the permutation argument (`Assembly`) used within a MockProver instance.
1607    pub fn permutation(&self) -> &Assembly {
1608        &self.permutation
1609    }
1610}
1611
1612#[cfg(test)]
1613mod tests {
1614    use halo2curves::pasta::Fp;
1615
1616    use super::{FailureLocation, MockProver, VerifyFailure};
1617    use crate::{
1618        circuit::{Layouter, SimpleFloorPlanner, Value},
1619        plonk::{
1620            sealed::SealedPhase, Advice, Any, Assigned, Circuit, Column, ConstraintSystem, Error,
1621            Expression, FirstPhase, Fixed, Instance, Selector, TableColumn,
1622        },
1623        poly::Rotation,
1624    };
1625
1626    #[test]
1627    fn unassigned_cell() {
1628        const K: u32 = 4;
1629
1630        #[derive(Clone)]
1631        struct FaultyCircuitConfig {
1632            a: Column<Advice>,
1633            b: Column<Advice>,
1634            q: Selector,
1635        }
1636
1637        struct FaultyCircuit {}
1638
1639        impl Circuit<Fp> for FaultyCircuit {
1640            type Config = FaultyCircuitConfig;
1641            type FloorPlanner = SimpleFloorPlanner;
1642            type Params = ();
1643            #[cfg(feature = "circuit-params")]
1644            fn params(&self) {}
1645
1646            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
1647                let a = meta.advice_column();
1648                let b = meta.advice_column();
1649                let q = meta.selector();
1650
1651                meta.create_gate("Equality check", |cells| {
1652                    let a = cells.query_advice(a, Rotation::prev());
1653                    let b = cells.query_advice(b, Rotation::cur());
1654                    let q = cells.query_selector(q);
1655
1656                    // If q is enabled, a and b must be assigned to.
1657                    vec![q * (a - b)]
1658                });
1659
1660                FaultyCircuitConfig { a, b, q }
1661            }
1662
1663            fn without_witnesses(&self) -> Self {
1664                Self {}
1665            }
1666
1667            fn synthesize(
1668                &self,
1669                config: Self::Config,
1670                mut layouter: impl Layouter<Fp>,
1671            ) -> Result<(), Error> {
1672                layouter.assign_region(
1673                    || "Faulty synthesis",
1674                    |mut region| {
1675                        // Enable the equality gate.
1676                        config.q.enable(&mut region, 1)?;
1677
1678                        // Assign a = 0.
1679                        region.assign_advice(
1680                            /*|| "a",*/ config.a,
1681                            0,
1682                            Value::known(Assigned::Trivial(Fp::zero())),
1683                        );
1684
1685                        // Name Column a
1686                        region.name_column(|| "This is annotated!", config.a);
1687
1688                        // Name Column b
1689                        region.name_column(|| "This is also annotated!", config.b);
1690
1691                        // Name Column a
1692                        region.name_column(|| "This is annotated!", config.a);
1693
1694                        // Name Column b
1695                        region.name_column(|| "This is also annotated!", config.b);
1696
1697                        // BUG: Forget to assign b = 0! This could go unnoticed during
1698                        // development, because cell values default to zero, which in this
1699                        // case is fine, but for other assignments would be broken.
1700                        Ok(())
1701                    },
1702                )
1703            }
1704        }
1705
1706        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
1707        assert_eq!(
1708            prover.verify(),
1709            Ok(()) // Axiom mock prover default assigns 0, so there is no bug
1710                   /*Err(vec![VerifyFailure::CellNotAssigned {
1711                       gate: (0, "Equality check").into(),
1712                       region: (0, "Faulty synthesis".to_owned()).into(),
1713                       gate_offset: 1,
1714                       column: Column::new(
1715                           1,
1716                           Any::Advice(Advice {
1717                               phase: FirstPhase.to_sealed()
1718                           })
1719                       ),
1720                       offset: 1,
1721                   }])*/
1722        );
1723    }
1724
1725    #[test]
1726    fn bad_lookup_any() {
1727        const K: u32 = 4;
1728
1729        #[derive(Clone)]
1730        struct FaultyCircuitConfig {
1731            a: Column<Advice>,
1732            table: Column<Instance>,
1733            advice_table: Column<Advice>,
1734            q: Selector,
1735        }
1736
1737        struct FaultyCircuit {}
1738
1739        impl Circuit<Fp> for FaultyCircuit {
1740            type Config = FaultyCircuitConfig;
1741            type FloorPlanner = SimpleFloorPlanner;
1742            type Params = ();
1743
1744            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
1745                let a = meta.advice_column();
1746                let q = meta.complex_selector();
1747                let table = meta.instance_column();
1748                let advice_table = meta.advice_column();
1749
1750                meta.annotate_lookup_any_column(table, || "Inst-Table");
1751                meta.enable_equality(table);
1752                meta.annotate_lookup_any_column(advice_table, || "Adv-Table");
1753                meta.enable_equality(advice_table);
1754
1755                meta.lookup_any("lookup", |cells| {
1756                    let a = cells.query_advice(a, Rotation::cur());
1757                    let q = cells.query_selector(q);
1758                    let advice_table = cells.query_advice(advice_table, Rotation::cur());
1759                    let table = cells.query_instance(table, Rotation::cur());
1760
1761                    // If q is enabled, a must be in the table.
1762                    // When q is not enabled, lookup the default value instead.
1763                    let not_q = Expression::Constant(Fp::one()) - q.clone();
1764                    let default = Expression::Constant(Fp::from(2));
1765                    vec![
1766                        (
1767                            q.clone() * a.clone() + not_q.clone() * default.clone(),
1768                            table,
1769                        ),
1770                        (q * a + not_q * default, advice_table),
1771                    ]
1772                });
1773
1774                FaultyCircuitConfig {
1775                    a,
1776                    q,
1777                    table,
1778                    advice_table,
1779                }
1780            }
1781
1782            fn without_witnesses(&self) -> Self {
1783                Self {}
1784            }
1785
1786            fn synthesize(
1787                &self,
1788                config: Self::Config,
1789                mut layouter: impl Layouter<Fp>,
1790            ) -> Result<(), Error> {
1791                // No assignment needed for the table as is an Instance Column.
1792
1793                layouter.assign_region(
1794                    || "Bad synthesis",
1795                    |mut region| {
1796                        // == Good synthesis ==
1797                        // Enable the lookup on rows 0 and 1.
1798                        config.q.enable(&mut region, 0)?;
1799                        config.q.enable(&mut region, 1)?;
1800
1801                        for i in 0..4 {
1802                            // Load Advice lookup table with Instance lookup table values.
1803                            region.assign_advice_from_instance(
1804                                || "Advice from instance tables",
1805                                config.table,
1806                                i,
1807                                config.advice_table,
1808                                i,
1809                            )?;
1810                        }
1811
1812                        // Assign a = 2 and a = 6.
1813                        region.assign_advice(config.a, 0, Value::known(Fp::from(2)));
1814                        region.assign_advice(config.a, 1, Value::known(Fp::from(6)));
1815
1816                        // == Faulty synthesis ==
1817                        // Enable the lookup on rows 0 and 1.
1818                        config.q.enable(&mut region, 2)?;
1819                        config.q.enable(&mut region, 3)?;
1820
1821                        // Assign a = 4.
1822                        region.assign_advice(config.a, 2, Value::known(Fp::from(4)));
1823
1824                        // BUG: Assign a = 5, which doesn't exist in the table!
1825                        region.assign_advice(config.a, 3, Value::known(Fp::from(5)));
1826
1827                        region.name_column(|| "Witness example", config.a);
1828
1829                        Ok(())
1830                    },
1831                )
1832            }
1833        }
1834
1835        let prover = MockProver::run(
1836            K,
1837            &FaultyCircuit {},
1838            // This is our "lookup table".
1839            vec![vec![
1840                Fp::from(1u64),
1841                Fp::from(2u64),
1842                Fp::from(4u64),
1843                Fp::from(6u64),
1844            ]],
1845        )
1846        .unwrap();
1847        assert_eq!(
1848            prover.verify(),
1849            Err(vec![VerifyFailure::Lookup {
1850                name: "lookup".to_string(),
1851                lookup_index: 0,
1852                location: FailureLocation::OutsideRegion { row: 3 }
1853            }])
1854        );
1855    }
1856
1857    #[test]
1858    fn bad_fixed_lookup() {
1859        const K: u32 = 4;
1860
1861        #[derive(Clone)]
1862        struct FaultyCircuitConfig {
1863            a: Column<Advice>,
1864            q: Selector,
1865            table: TableColumn,
1866        }
1867
1868        struct FaultyCircuit {}
1869
1870        impl Circuit<Fp> for FaultyCircuit {
1871            type Config = FaultyCircuitConfig;
1872            type FloorPlanner = SimpleFloorPlanner;
1873            #[cfg(feature = "circuit-params")]
1874            type Params = ();
1875
1876            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
1877                let a = meta.advice_column();
1878                let q = meta.complex_selector();
1879                let table = meta.lookup_table_column();
1880                meta.annotate_lookup_column(table, || "Table1");
1881
1882                meta.lookup("lookup", |cells| {
1883                    let a = cells.query_advice(a, Rotation::cur());
1884                    let q = cells.query_selector(q);
1885
1886                    // If q is enabled, a must be in the table.
1887                    // When q is not enabled, lookup the default value instead.
1888                    let not_q = Expression::Constant(Fp::one()) - q.clone();
1889                    let default = Expression::Constant(Fp::from(2));
1890                    vec![(q * a + not_q * default, table)]
1891                });
1892
1893                FaultyCircuitConfig { a, q, table }
1894            }
1895
1896            fn without_witnesses(&self) -> Self {
1897                Self {}
1898            }
1899
1900            fn synthesize(
1901                &self,
1902                config: Self::Config,
1903                mut layouter: impl Layouter<Fp>,
1904            ) -> Result<(), Error> {
1905                layouter.assign_table(
1906                    || "Doubling table",
1907                    |mut table| {
1908                        (1..(1 << (K - 1)))
1909                            .map(|i| {
1910                                table.assign_cell(
1911                                    || format!("table[{}] = {}", i, 2 * i),
1912                                    config.table,
1913                                    i - 1,
1914                                    || Value::known(Fp::from(2 * i as u64)),
1915                                )
1916                            })
1917                            .try_fold((), |_, res| res)
1918                    },
1919                )?;
1920
1921                layouter.assign_region(
1922                    || "Fauly synthesis",
1923                    |mut region| {
1924                        // == Good synhesis ==
1925                        // Enable the lookup on rows 0 and 1.
1926                        config.q.enable(&mut region, 0)?;
1927                        config.q.enable(&mut region, 1)?;
1928
1929                        // Assign a = 2 and a = 6.
1930                        region.assign_advice(
1931                            // || "a = 2",
1932                            config.a,
1933                            0,
1934                            Value::known(Assigned::Trivial(Fp::from(2))),
1935                        );
1936                        region.assign_advice(
1937                            // || "a = 6",
1938                            config.a,
1939                            1,
1940                            Value::known(Assigned::Trivial(Fp::from(6))),
1941                        );
1942
1943                        // == Faulty synthesis ==
1944                        // Enable the lookup on rows 2 and 3.
1945                        config.q.enable(&mut region, 2)?;
1946                        config.q.enable(&mut region, 3)?;
1947
1948                        // Assign a = 4.
1949                        region.assign_advice(
1950                            config.a,
1951                            2,
1952                            Value::known(Assigned::Trivial(Fp::from(4))),
1953                        );
1954
1955                        // BUG: Assign a = 5, which doesn't exist in the table!
1956                        region.assign_advice(
1957                            config.a,
1958                            3,
1959                            Value::known(Assigned::Trivial(Fp::from(5))),
1960                        );
1961
1962                        region.name_column(|| "Witness example", config.a);
1963
1964                        region.name_column(|| "Witness example", config.a);
1965
1966                        Ok(())
1967                    },
1968                )
1969            }
1970        }
1971
1972        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
1973        assert_eq!(
1974            prover.verify(),
1975            Err(vec![VerifyFailure::Lookup {
1976                name: "lookup".to_string(),
1977                lookup_index: 0,
1978                location: FailureLocation::OutsideRegion { row: 3 }
1979            }])
1980        );
1981    }
1982
1983    #[test]
1984    fn contraint_unsatisfied() {
1985        const K: u32 = 4;
1986
1987        #[derive(Clone)]
1988        struct FaultyCircuitConfig {
1989            a: Column<Advice>,
1990            b: Column<Advice>,
1991            c: Column<Advice>,
1992            d: Column<Fixed>,
1993            q: Selector,
1994        }
1995
1996        struct FaultyCircuit {}
1997
1998        impl Circuit<Fp> for FaultyCircuit {
1999            type Config = FaultyCircuitConfig;
2000            type FloorPlanner = SimpleFloorPlanner;
2001            type Params = ();
2002
2003            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
2004                let a = meta.advice_column();
2005                let b = meta.advice_column();
2006                let c = meta.advice_column();
2007                let d = meta.fixed_column();
2008                let q = meta.selector();
2009
2010                meta.create_gate("Equality check", |cells| {
2011                    let a = cells.query_advice(a, Rotation::cur());
2012                    let b = cells.query_advice(b, Rotation::cur());
2013                    let c = cells.query_advice(c, Rotation::cur());
2014                    let d = cells.query_fixed(d, Rotation::cur());
2015                    let q = cells.query_selector(q);
2016
2017                    // If q is enabled, a and b must be assigned to.
2018                    vec![q * (a - b) * (c - d)]
2019                });
2020
2021                FaultyCircuitConfig { a, b, c, d, q }
2022            }
2023
2024            fn without_witnesses(&self) -> Self {
2025                Self {}
2026            }
2027
2028            fn synthesize(
2029                &self,
2030                config: Self::Config,
2031                mut layouter: impl Layouter<Fp>,
2032            ) -> Result<(), Error> {
2033                layouter.assign_region(
2034                    || "Wrong synthesis",
2035                    |mut region| {
2036                        // == Correct synthesis ==
2037                        // Enable the equality gate.
2038                        config.q.enable(&mut region, 0)?;
2039
2040                        // Assign a = 1.
2041                        region.assign_advice(config.a, 0, Value::known(Fp::one()));
2042
2043                        // Assign b = 1.
2044                        region.assign_advice(config.b, 0, Value::known(Fp::one()));
2045
2046                        // Assign c = 5.
2047                        region.assign_advice(config.c, 0, Value::known(Fp::from(5u64)));
2048                        // Assign d = 7.
2049                        region.assign_fixed(config.d, 0, Fp::from(7u64));
2050
2051                        // == Wrong synthesis ==
2052                        // Enable the equality gate.
2053                        config.q.enable(&mut region, 1)?;
2054
2055                        // Assign a = 1.
2056                        region.assign_advice(config.a, 1, Value::known(Fp::one()));
2057
2058                        // Assign b = 0.
2059                        region.assign_advice(config.b, 1, Value::known(Fp::zero()));
2060
2061                        // Name Column a
2062                        region.name_column(|| "This is Advice!", config.a);
2063                        // Name Column b
2064                        region.name_column(|| "This is Advice too!", config.b);
2065
2066                        // Assign c = 5.
2067                        region.assign_advice(config.c, 1, Value::known(Fp::from(5u64)));
2068                        // Assign d = 7.
2069                        region.assign_fixed(config.d, 1, Fp::from(7u64));
2070
2071                        // Name Column c
2072                        region.name_column(|| "Another one!", config.c);
2073                        // Name Column d
2074                        region.name_column(|| "This is a Fixed!", config.d);
2075
2076                        // Note that none of the terms cancel eachother. Therefore we will have a constraint that is non satisfied for
2077                        // the `Equalty check` gate.
2078                        Ok(())
2079                    },
2080                )
2081            }
2082        }
2083
2084        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
2085        assert_eq!(
2086            prover.verify(),
2087            Err(vec![VerifyFailure::ConstraintNotSatisfied {
2088                constraint: ((0, "Equality check").into(), 0, "").into(),
2089                location: FailureLocation::InRegion {
2090                    region: (0, "Wrong synthesis").into(),
2091                    offset: 1,
2092                },
2093                cell_values: vec![
2094                    (
2095                        (
2096                            (
2097                                Any::Advice(Advice {
2098                                    phase: FirstPhase.to_sealed()
2099                                }),
2100                                0
2101                            )
2102                                .into(),
2103                            0
2104                        )
2105                            .into(),
2106                        "1".to_string()
2107                    ),
2108                    (
2109                        (
2110                            (
2111                                Any::Advice(Advice {
2112                                    phase: FirstPhase.to_sealed()
2113                                }),
2114                                1
2115                            )
2116                                .into(),
2117                            0
2118                        )
2119                            .into(),
2120                        "0".to_string()
2121                    ),
2122                    (
2123                        (
2124                            (
2125                                Any::Advice(Advice {
2126                                    phase: FirstPhase.to_sealed()
2127                                }),
2128                                2
2129                            )
2130                                .into(),
2131                            0
2132                        )
2133                            .into(),
2134                        "0x5".to_string()
2135                    ),
2136                    (((Any::Fixed, 0).into(), 0).into(), "0x7".to_string()),
2137                ],
2138            },])
2139        )
2140    }
2141}