jf_relation/
constraint_system.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! Definitions and constructions of plonk constraint system
8use crate::{
9    constants::{compute_coset_representatives, GATE_WIDTH, N_MUL_SELECTORS},
10    gates::*,
11    CircuitError,
12    CircuitError::*,
13};
14use ark_ff::{FftField, Field, PrimeField};
15use ark_poly::{
16    domain::Radix2EvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial,
17    EvaluationDomain,
18};
19use ark_std::{boxed::Box, cmp::max, format, string::ToString, vec, vec::Vec};
20use hashbrown::{HashMap, HashSet};
21use jf_utils::par_utils::parallelizable_slice_iter;
22#[cfg(feature = "parallel")]
23use rayon::prelude::*;
24
25/// An index to a gate in circuit.
26pub type GateId = usize;
27/// An index to the type of gate wires.
28/// There are 4 different types of input gate wires (with indices 0..3),
29/// 1 type of output gate wires (with index 4), and 1 type of lookup gate wires
30/// (with index 5).
31pub type WireId = usize;
32/// An index to one of the witness values.
33pub type Variable = usize;
34/// An index to a witness value of boolean type.
35#[derive(Debug, Clone, Copy)]
36pub struct BoolVar(pub usize);
37
38impl From<BoolVar> for Variable {
39    fn from(bv: BoolVar) -> Self {
40        bv.0
41    }
42}
43
44impl BoolVar {
45    /// Create a `BoolVar` without any check. Be careful!
46    /// This is an internal API, shouldn't be used unless you know what you are
47    /// doing. Normally you should only construct `BoolVar` through
48    /// `Circuit::create_boolean_variable()`.
49    pub(crate) fn new_unchecked(inner: usize) -> Self {
50        Self(inner)
51    }
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
55/// Enum for each type of Plonk scheme.
56pub enum PlonkType {
57    /// TurboPlonk
58    TurboPlonk,
59    /// TurboPlonk that supports Plookup
60    UltraPlonk,
61}
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
64/// Enum for each type of mergeable circuit. We can only merge circuits from
65/// different types.
66pub enum MergeableCircuitType {
67    /// First type
68    TypeA,
69    /// Second type
70    TypeB,
71}
72
73/// An interface for Plonk constraint systems.
74pub trait Circuit<F: Field> {
75    /// The number of constraints.
76    fn num_gates(&self) -> usize;
77
78    /// The number of variables.
79    fn num_vars(&self) -> usize;
80
81    /// The number of public input variables.
82    fn num_inputs(&self) -> usize;
83
84    /// The number of wire types of the circuit.
85    /// E.g., UltraPlonk has 4 different types of input wires, 1 type of output
86    /// wires, and 1 type of lookup wires.
87    fn num_wire_types(&self) -> usize;
88
89    /// The list of public input values.
90    fn public_input(&self) -> Result<Vec<F>, CircuitError>;
91
92    /// Check circuit satisfiability against a public input.
93    fn check_circuit_satisfiability(&self, pub_input: &[F]) -> Result<(), CircuitError>;
94
95    /// Add a constant variable to the circuit; return the index of the
96    /// variable.
97    fn create_constant_variable(&mut self, val: F) -> Result<Variable, CircuitError>;
98
99    /// Add a variable to the circuit; return the index of the variable.
100    fn create_variable(&mut self, val: F) -> Result<Variable, CircuitError>;
101
102    /// Add a bool variable to the circuit; return the index of the variable.
103    fn create_boolean_variable(&mut self, val: bool) -> Result<BoolVar, CircuitError> {
104        let val_scalar = if val { F::one() } else { F::zero() };
105        let var = self.create_variable(val_scalar)?;
106        self.enforce_bool(var)?;
107        Ok(BoolVar(var))
108    }
109
110    /// Add a public input variable; return the index of the variable.
111    fn create_public_variable(&mut self, val: F) -> Result<Variable, CircuitError>;
112
113    /// Add a public bool variable to the circuit; return the index of the
114    /// variable.
115    fn create_public_boolean_variable(&mut self, val: bool) -> Result<BoolVar, CircuitError> {
116        let val_scalar = if val { F::one() } else { F::zero() };
117        let var = self.create_public_variable(val_scalar)?;
118        Ok(BoolVar(var))
119    }
120
121    /// Set a variable to a public variable
122    fn set_variable_public(&mut self, var: Variable) -> Result<(), CircuitError>;
123
124    /// Return a default variable with value zero.
125    fn zero(&self) -> Variable;
126
127    /// Return a default variable with value one.
128    fn one(&self) -> Variable;
129
130    /// Return a default variable with value `false` (namely zero).
131    fn false_var(&self) -> BoolVar {
132        BoolVar::new_unchecked(self.zero())
133    }
134
135    /// Return a default variable with value `true` (namely one).
136    fn true_var(&self) -> BoolVar {
137        BoolVar::new_unchecked(self.one())
138    }
139
140    /// Return the witness value of variable `idx`.
141    /// Return error if the input variable is invalid.
142    fn witness(&self, idx: Variable) -> Result<F, CircuitError>;
143
144    /// Common gates that should be implemented in any constraint systems.
145    ///
146    /// Constrain a variable to a constant.
147    /// Return error if `var` is an invalid variable.
148    fn enforce_constant(&mut self, var: Variable, constant: F) -> Result<(), CircuitError>;
149
150    /// Constrain variable `c` to the addition of `a` and `b`.
151    /// Return error if the input variables are invalid.
152    fn add_gate(&mut self, a: Variable, b: Variable, c: Variable) -> Result<(), CircuitError>;
153
154    /// Obtain a variable representing an addition.
155    /// Return the index of the variable.
156    /// Return error if the input variables are invalid.
157    fn add(&mut self, a: Variable, b: Variable) -> Result<Variable, CircuitError>;
158
159    /// Constrain variable `c` to the subtraction of `a` and `b`.
160    /// Return error if the input variables are invalid.
161    fn sub_gate(&mut self, a: Variable, b: Variable, c: Variable) -> Result<(), CircuitError>;
162
163    /// Obtain a variable representing a subtraction.
164    /// Return the index of the variable.
165    /// Return error if the input variables are invalid.
166    fn sub(&mut self, a: Variable, b: Variable) -> Result<Variable, CircuitError>;
167
168    /// Constrain variable `c` to the multiplication of `a` and `b`.
169    /// Return error if the input variables are invalid.
170    fn mul_gate(&mut self, a: Variable, b: Variable, c: Variable) -> Result<(), CircuitError>;
171
172    /// Obtain a variable representing a multiplication.
173    /// Return the index of the variable.
174    /// Return error if the input variables are invalid.
175    fn mul(&mut self, a: Variable, b: Variable) -> Result<Variable, CircuitError>;
176
177    /// Constrain a variable to a bool.
178    /// Return error if the input is invalid.
179    fn enforce_bool(&mut self, a: Variable) -> Result<(), CircuitError>;
180
181    /// Constrain two variables to have the same value.
182    /// Return error if the input variables are invalid.
183    fn enforce_equal(&mut self, a: Variable, b: Variable) -> Result<(), CircuitError>;
184
185    /// Pad the circuit with n dummy gates
186    fn pad_gates(&mut self, n: usize);
187
188    /// Plookup-related methods.
189    /// Return true if the circuit support lookup gates.
190    fn support_lookup(&self) -> bool;
191}
192
193// The sorted concatenation of the lookup table and the witness values to be
194// checked in lookup gates. It also includes 2 polynomials that interpolate the
195// sorted vector.
196pub(crate) type SortedLookupVecAndPolys<F> = (Vec<F>, DensePolynomial<F>, DensePolynomial<F>);
197
198/// An interface that transforms Plonk circuits to polynomial used by
199/// Plonk-based SNARKs.
200pub trait Arithmetization<F: FftField>: Circuit<F> {
201    /// The required SRS size for the circuit.
202    fn srs_size(&self) -> Result<usize, CircuitError>;
203
204    /// Get the size of the evaluation domain for arithmetization (after circuit
205    /// has been finalized).
206    fn eval_domain_size(&self) -> Result<usize, CircuitError>;
207
208    /// Compute and return selector polynomials.
209    /// Return an error if the circuit has not been finalized yet.
210    fn compute_selector_polynomials(&self) -> Result<Vec<DensePolynomial<F>>, CircuitError>;
211
212    /// Compute and return extended permutation polynomials.
213    /// Return an error if the circuit has not been finalized yet.
214    fn compute_extended_permutation_polynomials(
215        &self,
216    ) -> Result<Vec<DensePolynomial<F>>, CircuitError>;
217
218    /// Compute and return the product polynomial for permutation arguments.
219    /// Return an error if the circuit has not been finalized yet.
220    fn compute_prod_permutation_polynomial(
221        &self,
222        beta: &F,
223        gamma: &F,
224    ) -> Result<DensePolynomial<F>, CircuitError>;
225
226    /// Compute and return the list of wiring witness polynomials.
227    /// Return an error if the circuit has not been finalized yet.
228    fn compute_wire_polynomials(&self) -> Result<Vec<DensePolynomial<F>>, CircuitError>;
229
230    /// Compute and return the public input polynomial.
231    /// Return an error if the circuit has not been finalized yet.
232    /// The IO gates of the circuit are guaranteed to be in the front.
233    fn compute_pub_input_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError>;
234
235    /// Plookup-related methods
236    /// Return default errors if the constraint system does not support lookup
237    /// gates.
238    ///
239    /// Compute and return the polynomial that interpolates the range table
240    /// elements. Return an error if the circuit does not support lookup or
241    /// has not been finalized yet.
242    fn compute_range_table_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
243        Err(CircuitError::LookupUnsupported)
244    }
245
246    /// Compute and return the polynomial that interpolates the key table
247    /// elements. Return an error if the circuit does not support lookup or
248    /// has not been finalized yet.
249    fn compute_key_table_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
250        Err(CircuitError::LookupUnsupported)
251    }
252
253    /// Compute and return the polynomial that interpolates the table domain
254    /// separation ids. Return an error if the circuit does not support
255    /// lookup or has not been finalized.
256    fn compute_table_dom_sep_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
257        Err(CircuitError::LookupUnsupported)
258    }
259
260    /// Compute and return the polynomial that interpolates the lookup domain
261    /// sepration selectors for the lookup gates. Return an error if the
262    /// circuit does not support lookup or has not been finalized.
263    fn compute_q_dom_sep_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
264        Err(CircuitError::LookupUnsupported)
265    }
266
267    /// Compute and return the combined lookup table vector given random
268    /// challenge `tau`.
269    fn compute_merged_lookup_table(&self, _tau: F) -> Result<Vec<F>, CircuitError> {
270        Err(CircuitError::LookupUnsupported)
271    }
272
273    /// Compute the sorted concatenation of the (merged) lookup table and the
274    /// witness values to be checked in lookup gates. Return the sorted
275    /// vector and 2 polynomials that interpolate the vector. Return an
276    /// error if the circuit does not support lookup or has not been
277    /// finalized yet.
278    fn compute_lookup_sorted_vec_polynomials(
279        &self,
280        _tau: F,
281        _lookup_table: &[F],
282    ) -> Result<SortedLookupVecAndPolys<F>, CircuitError> {
283        Err(CircuitError::LookupUnsupported)
284    }
285
286    /// Compute and return the product polynomial for Plookup arguments.
287    /// `beta` and `gamma` are random challenges, `sorted_vec` is the sorted
288    /// concatenation of the lookup table and the lookup witnesses.
289    /// Return an error if the circuit does not support lookup or
290    /// has not been finalized yet.
291    fn compute_lookup_prod_polynomial(
292        &self,
293        _tau: &F,
294        _beta: &F,
295        _gamma: &F,
296        _lookup_table: &[F],
297        _sorted_vec: &[F],
298    ) -> Result<DensePolynomial<F>, CircuitError> {
299        Err(CircuitError::LookupUnsupported)
300    }
301}
302
303/// The wire type identifier for range gates.
304const RANGE_WIRE_ID: usize = 5;
305/// The wire type identifier for the key index in a lookup gate
306const LOOKUP_KEY_WIRE_ID: usize = 0;
307/// The wire type identifiers for the searched pair values in a lookup gate
308const LOOKUP_VAL_1_WIRE_ID: usize = 1;
309const LOOKUP_VAL_2_WIRE_ID: usize = 2;
310/// The wire type identifiers for the pair values in the lookup table
311const TABLE_VAL_1_WIRE_ID: usize = 3;
312const TABLE_VAL_2_WIRE_ID: usize = 4;
313
314/// Hardcoded parameters for Plonk systems.
315#[derive(Debug, Clone, Copy)]
316struct PlonkParams {
317    /// The Plonk type of the circuit.
318    plonk_type: PlonkType,
319
320    /// The bit length of a range-check. None for TurboPlonk.
321    range_bit_len: Option<usize>,
322}
323
324impl PlonkParams {
325    fn init(plonk_type: PlonkType, range_bit_len: Option<usize>) -> Result<Self, CircuitError> {
326        if plonk_type == PlonkType::TurboPlonk {
327            return Ok(Self {
328                plonk_type,
329                range_bit_len: None,
330            });
331        }
332        if range_bit_len.is_none() {
333            return Err(ParameterError(
334                "range bit len cannot be none for UltraPlonk".to_string(),
335            ));
336        }
337
338        Ok(Self {
339            plonk_type,
340            range_bit_len,
341        })
342    }
343}
344
345/// A specific Plonk circuit instantiation.
346#[derive(Debug, Clone)]
347pub struct PlonkCircuit<F>
348where
349    F: FftField,
350{
351    /// The number of variables.
352    num_vars: usize,
353
354    /// The gate of each (algebraic) constraint
355    gates: Vec<Box<dyn Gate<F>>>,
356    /// The map from arithmetic/lookup gate wires to variables.
357    wire_variables: [Vec<Variable>; GATE_WIDTH + 2],
358    /// The IO gates for the list of public input variables.
359    pub_input_gate_ids: Vec<GateId>,
360    /// The actual values of variables.
361    witness: Vec<F>,
362
363    /// The permutation over wires.
364    /// Each algebraic gate has 5 wires, i.e., 4 input wires and an output
365    /// wire; each lookup gate has a single wire that maps to a witness to
366    /// be checked over the lookup table. In total there are 6 * n wires
367    /// where n is the (padded) number of arithmetic/lookup gates.  
368    /// We build a permutation over the set of wires so that each set of wires
369    /// that map to the same witness forms a cycle.
370    ///
371    /// Each wire is represented by a pair (`WireId, GateId`) so that the wire
372    /// is in the `GateId`-th arithmetic/lookup gate and `WireId` represents
373    /// the wire type (e.g., 0 represents 1st input wires, 4 represents
374    /// output wires, and 5 represents lookup wires).
375    wire_permutation: Vec<(WireId, GateId)>,
376    /// The extended identity permutation.
377    extended_id_permutation: Vec<F>,
378    /// The number of wire types. 5 for TurboPlonk and 6 for UltraPlonk.
379    num_wire_types: usize,
380
381    /// The evaluation domain for arithmetization of the circuit into various
382    /// polynomials. This is only relevant after the circuit is finalized for
383    /// arithmetization, by default it is a domain with size 1 (only with
384    /// element 0).
385    eval_domain: Radix2EvaluationDomain<F>,
386
387    /// The Plonk parameters.
388    plonk_params: PlonkParams,
389
390    /// The number of key-value table elements being inserted.
391    num_table_elems: usize,
392
393    /// The lookup gates indices for the inserted tables.
394    /// For each inserted table, the 1st value is the start id of the table,
395    /// the 2nd values is the length of the table.
396    table_gate_ids: Vec<(GateId, usize)>,
397}
398
399impl<F: FftField> Default for PlonkCircuit<F> {
400    fn default() -> Self {
401        let params = PlonkParams::init(PlonkType::TurboPlonk, None).unwrap();
402        Self::new(params)
403    }
404}
405
406impl<F: FftField> PlonkCircuit<F> {
407    /// Construct a new circuit with type `plonk_type`.
408    fn new(plonk_params: PlonkParams) -> Self {
409        let zero = F::zero();
410        let one = F::one();
411        let mut circuit = Self {
412            num_vars: 2,
413            witness: vec![zero, one],
414            gates: vec![],
415            // size is `num_wire_types`
416            wire_variables: [vec![], vec![], vec![], vec![], vec![], vec![]],
417            pub_input_gate_ids: vec![],
418
419            wire_permutation: vec![],
420            extended_id_permutation: vec![],
421            num_wire_types: GATE_WIDTH
422                + 1
423                + match plonk_params.plonk_type {
424                    PlonkType::TurboPlonk => 0,
425                    PlonkType::UltraPlonk => 1,
426                },
427            eval_domain: Radix2EvaluationDomain::new(1).unwrap(),
428            plonk_params,
429            num_table_elems: 0,
430            table_gate_ids: vec![],
431        };
432        // Constrain variables `0`/`1` to have value 0/1.
433        circuit.enforce_constant(0, zero).unwrap(); // safe unwrap
434        circuit.enforce_constant(1, one).unwrap(); // safe unwrap
435        circuit
436    }
437
438    /// Construct a new TurboPlonk circuit.
439    pub fn new_turbo_plonk() -> Self {
440        let plonk_params = PlonkParams::init(PlonkType::TurboPlonk, None).unwrap(); // safe unwrap
441        Self::new(plonk_params)
442    }
443
444    /// Construct a new UltraPlonk circuit.
445    pub fn new_ultra_plonk(range_bit_len: usize) -> Self {
446        let plonk_params = PlonkParams::init(PlonkType::UltraPlonk, Some(range_bit_len)).unwrap(); // safe unwrap
447        Self::new(plonk_params)
448    }
449
450    /// Insert a general (algebraic) gate
451    /// * `wire_vars` - wire variables. Each of these variables must be in range
452    /// * `gate` - specific gate to be inserted
453    /// * `returns` - an error if some verification fails
454    pub fn insert_gate(
455        &mut self,
456        wire_vars: &[Variable; GATE_WIDTH + 1],
457        gate: Box<dyn Gate<F>>,
458    ) -> Result<(), CircuitError> {
459        self.check_finalize_flag(false)?;
460
461        for (wire_var, wire_variable) in wire_vars
462            .iter()
463            .zip(self.wire_variables.iter_mut().take(GATE_WIDTH + 1))
464        {
465            wire_variable.push(*wire_var)
466        }
467
468        self.gates.push(gate);
469        Ok(())
470    }
471
472    /// Add a range_check gate that checks whether a variable is in the range
473    /// [0, range_size). Return an error if the circuit does not support
474    /// lookup.
475    pub fn add_range_check_variable(&mut self, var: Variable) -> Result<(), CircuitError> {
476        self.check_plonk_type(PlonkType::UltraPlonk)?;
477        self.check_finalize_flag(false)?;
478        self.check_var_bound(var)?;
479        self.wire_variables[RANGE_WIRE_ID].push(var);
480        Ok(())
481    }
482
483    #[inline]
484    /// Checks if a variable is strictly less than the number of variables.
485    /// This function must be invoked for each gate as this check is not applied
486    /// in the function `insert_gate`
487    /// * `var` - variable to check
488    /// * `returns` - Error if the variable is out of bound (i.e. >= number of
489    ///   variables)
490    pub fn check_var_bound(&self, var: Variable) -> Result<(), CircuitError> {
491        if var >= self.num_vars {
492            return Err(VarIndexOutOfBound(var, self.num_vars));
493        }
494        Ok(())
495    }
496
497    /// Check if a list of variables are strictly less than the number of
498    /// variables.
499    /// * `vars` - variables to check
500    /// * `returns` - Error if the variable is out of bound (i.e. >= number of
501    ///   variables)
502    pub fn check_vars_bound(&self, vars: &[Variable]) -> Result<(), CircuitError> {
503        for &var in vars {
504            self.check_var_bound(var)?
505        }
506        Ok(())
507    }
508
509    /// Change the value of a variable. Only used for testing.
510    // TODO: make this function test only.
511    pub fn witness_mut(&mut self, idx: Variable) -> &mut F {
512        &mut self.witness[idx]
513    }
514
515    /// Get the mutable reference of the inserted table ids.
516    pub(crate) fn table_gate_ids_mut(&mut self) -> &mut Vec<(GateId, usize)> {
517        &mut self.table_gate_ids
518    }
519
520    /// Get the mutable reference of the number of inserted table elements.
521    pub(crate) fn num_table_elems_mut(&mut self) -> &mut usize {
522        &mut self.num_table_elems
523    }
524
525    /// Get the number of inserted table elements.
526    pub(crate) fn num_table_elems(&self) -> usize {
527        self.num_table_elems
528    }
529
530    /// The bit length of UltraPlonk range gates.
531    pub fn range_bit_len(&self) -> Result<usize, CircuitError> {
532        if self.plonk_params.plonk_type != PlonkType::UltraPlonk {
533            return Err(ParameterError(
534                "call range_bit_len() with non-ultraplonk circuit".to_string(),
535            ));
536        }
537        Ok(self.plonk_params.range_bit_len.unwrap()) // safe unwrap
538    }
539
540    /// The range size of UltraPlonk range gates.
541    pub fn range_size(&self) -> Result<usize, CircuitError> {
542        Ok(1 << self.range_bit_len()?)
543    }
544
545    /// creating a `BoolVar` without checking if `v` is a boolean value!
546    /// You should absolutely sure about what you are doing.
547    /// You should normally only use this API if you already enforce `v` to be a
548    /// boolean value using other constraints.
549    pub(crate) fn create_boolean_variable_unchecked(
550        &mut self,
551        a: F,
552    ) -> Result<BoolVar, CircuitError> {
553        let var = self.create_variable(a)?;
554        Ok(BoolVar::new_unchecked(var))
555    }
556}
557
558impl<F: FftField> Circuit<F> for PlonkCircuit<F> {
559    fn num_gates(&self) -> usize {
560        self.gates.len()
561    }
562
563    fn num_vars(&self) -> usize {
564        self.num_vars
565    }
566
567    fn num_inputs(&self) -> usize {
568        self.pub_input_gate_ids.len()
569    }
570
571    fn num_wire_types(&self) -> usize {
572        self.num_wire_types
573    }
574
575    fn public_input(&self) -> Result<Vec<F>, CircuitError> {
576        self.pub_input_gate_ids
577            .iter()
578            .map(|&gate_id| -> Result<F, CircuitError> {
579                let var = self.wire_variables[GATE_WIDTH][gate_id];
580                self.witness(var)
581            })
582            .collect::<Result<Vec<F>, CircuitError>>()
583    }
584
585    fn check_circuit_satisfiability(&self, pub_input: &[F]) -> Result<(), CircuitError> {
586        if pub_input.len() != self.num_inputs() {
587            return Err(PubInputLenMismatch(
588                pub_input.len(),
589                self.pub_input_gate_ids.len(),
590            ));
591        }
592        // Check public I/O gates
593        for (i, gate_id) in self.pub_input_gate_ids.iter().enumerate() {
594            let pi = pub_input[i];
595            self.check_gate(*gate_id, &pi)?;
596        }
597        // Check rest of the gates
598        for gate_id in 0..self.num_gates() {
599            if !self.is_io_gate(gate_id) {
600                let pi = F::zero();
601                self.check_gate(gate_id, &pi)?;
602            }
603        }
604        // Check range/lookup gates if the circuit supports lookup
605        if self.plonk_params.plonk_type == PlonkType::UltraPlonk {
606            // range gates
607            for idx in 0..self.wire_variables[RANGE_WIRE_ID].len() {
608                self.check_range_gate(idx)?
609            }
610            // key-value map lookup gates
611            let mut key_val_table = HashSet::new();
612            key_val_table.insert((F::zero(), F::zero(), F::zero(), F::zero()));
613            let q_lookup_vec = self.q_lookup();
614            let q_dom_sep_vec = self.q_dom_sep();
615            let table_key_vec = self.table_key_vec();
616            let table_dom_sep_vec = self.table_dom_sep_vec();
617            // insert table elements
618            for (gate_id, ((&q_lookup, &table_dom_sep), &table_key)) in q_lookup_vec
619                .iter()
620                .zip(table_dom_sep_vec.iter())
621                .zip(table_key_vec.iter())
622                .enumerate()
623            {
624                if q_lookup != F::zero() {
625                    let val0 = self.witness(self.wire_variable(TABLE_VAL_1_WIRE_ID, gate_id))?;
626                    let val1 = self.witness(self.wire_variable(TABLE_VAL_2_WIRE_ID, gate_id))?;
627                    key_val_table.insert((table_dom_sep, table_key, val0, val1));
628                }
629            }
630            // check lookups
631            for (gate_id, (&q_lookup, &q_dom_sep)) in
632                q_lookup_vec.iter().zip(q_dom_sep_vec.iter()).enumerate()
633            {
634                if q_lookup != F::zero() {
635                    let key = self.witness(self.wire_variable(LOOKUP_KEY_WIRE_ID, gate_id))?;
636                    let val0 = self.witness(self.wire_variable(LOOKUP_VAL_1_WIRE_ID, gate_id))?;
637                    let val1 = self.witness(self.wire_variable(LOOKUP_VAL_2_WIRE_ID, gate_id))?;
638                    if !key_val_table.contains(&(q_dom_sep, key, val0, val1)) {
639                        return Err(GateCheckFailure(
640                            gate_id,
641                            format!(
642                                "Lookup gate failed: ({q_dom_sep}, {key}, {val0}, {val1}) not in the table",
643                            ),
644                        ));
645                    }
646                }
647            }
648        }
649        Ok(())
650    }
651
652    fn create_constant_variable(&mut self, val: F) -> Result<Variable, CircuitError> {
653        let var = self.create_variable(val)?;
654        self.enforce_constant(var, val)?;
655        Ok(var)
656    }
657
658    fn create_variable(&mut self, val: F) -> Result<Variable, CircuitError> {
659        self.check_finalize_flag(false)?;
660        self.witness.push(val);
661        self.num_vars += 1;
662        // the index is from `0` to `num_vars - 1`
663        Ok(self.num_vars - 1)
664    }
665
666    fn create_public_variable(&mut self, val: F) -> Result<Variable, CircuitError> {
667        let var = self.create_variable(val)?;
668        self.set_variable_public(var)?;
669        Ok(var)
670    }
671
672    fn set_variable_public(&mut self, var: Variable) -> Result<(), CircuitError> {
673        self.check_finalize_flag(false)?;
674        self.pub_input_gate_ids.push(self.num_gates());
675
676        // Create an io gate that forces `witness[var] = public_input`.
677        let wire_vars = &[0, 0, 0, 0, var];
678        self.insert_gate(wire_vars, Box::new(IoGate))?;
679        Ok(())
680    }
681
682    /// Default zero variable
683    fn zero(&self) -> Variable {
684        0
685    }
686
687    /// Default one variable
688    fn one(&self) -> Variable {
689        1
690    }
691
692    fn witness(&self, idx: Variable) -> Result<F, CircuitError> {
693        self.check_var_bound(idx)?;
694        Ok(self.witness[idx])
695    }
696
697    fn enforce_constant(&mut self, var: Variable, constant: F) -> Result<(), CircuitError> {
698        self.check_var_bound(var)?;
699
700        let wire_vars = &[0, 0, 0, 0, var];
701        self.insert_gate(wire_vars, Box::new(ConstantGate(constant)))?;
702        Ok(())
703    }
704
705    fn add_gate(&mut self, a: Variable, b: Variable, c: Variable) -> Result<(), CircuitError> {
706        self.check_var_bound(a)?;
707        self.check_var_bound(b)?;
708        self.check_var_bound(c)?;
709
710        let wire_vars = &[a, b, 0, 0, c];
711        self.insert_gate(wire_vars, Box::new(AdditionGate))?;
712        Ok(())
713    }
714
715    fn add(&mut self, a: Variable, b: Variable) -> Result<Variable, CircuitError> {
716        self.check_var_bound(a)?;
717        self.check_var_bound(b)?;
718        let val = self.witness(a)? + self.witness(b)?;
719        let c = self.create_variable(val)?;
720        self.add_gate(a, b, c)?;
721        Ok(c)
722    }
723
724    fn sub_gate(&mut self, a: Variable, b: Variable, c: Variable) -> Result<(), CircuitError> {
725        self.check_var_bound(a)?;
726        self.check_var_bound(b)?;
727        self.check_var_bound(c)?;
728
729        let wire_vars = &[a, b, 0, 0, c];
730        self.insert_gate(wire_vars, Box::new(SubtractionGate))?;
731        Ok(())
732    }
733
734    fn sub(&mut self, a: Variable, b: Variable) -> Result<Variable, CircuitError> {
735        self.check_var_bound(a)?;
736        self.check_var_bound(b)?;
737        let val = self.witness(a)? - self.witness(b)?;
738        let c = self.create_variable(val)?;
739        self.sub_gate(a, b, c)?;
740        Ok(c)
741    }
742
743    fn mul_gate(&mut self, a: Variable, b: Variable, c: Variable) -> Result<(), CircuitError> {
744        self.check_var_bound(a)?;
745        self.check_var_bound(b)?;
746        self.check_var_bound(c)?;
747
748        let wire_vars = &[a, b, 0, 0, c];
749        self.insert_gate(wire_vars, Box::new(MultiplicationGate))?;
750        Ok(())
751    }
752
753    fn mul(&mut self, a: Variable, b: Variable) -> Result<Variable, CircuitError> {
754        self.check_var_bound(a)?;
755        self.check_var_bound(b)?;
756        let val = self.witness(a)? * self.witness(b)?;
757        let c = self.create_variable(val)?;
758        self.mul_gate(a, b, c)?;
759        Ok(c)
760    }
761
762    fn enforce_bool(&mut self, a: Variable) -> Result<(), CircuitError> {
763        self.check_var_bound(a)?;
764
765        let wire_vars = &[a, a, 0, 0, a];
766        self.insert_gate(wire_vars, Box::new(BoolGate))?;
767        Ok(())
768    }
769
770    fn enforce_equal(&mut self, a: Variable, b: Variable) -> Result<(), CircuitError> {
771        self.check_var_bound(a)?;
772        self.check_var_bound(b)?;
773
774        let wire_vars = &[a, b, 0, 0, 0];
775        self.insert_gate(wire_vars, Box::new(EqualityGate))?;
776        Ok(())
777    }
778
779    fn pad_gates(&mut self, n: usize) {
780        // TODO: FIXME
781        // this is interesting...
782        // if we insert a PaddingGate
783        // the padded gate does not have a gate_id, and will bug
784        // when we check circuit satisfiability
785        // we temporarily insert equality gate to by pass the issue
786        let wire_vars = &[self.zero(), self.zero(), 0, 0, 0];
787        for _ in 0..n {
788            self.insert_gate(wire_vars, Box::new(EqualityGate)).unwrap();
789        }
790    }
791
792    // Plookup-related methods
793    //
794    fn support_lookup(&self) -> bool {
795        self.plonk_params.plonk_type == PlonkType::UltraPlonk
796    }
797}
798
799/// Private helper methods
800impl<F: FftField> PlonkCircuit<F> {
801    /// Check correctness of the idx-th range gate. Return an error if the
802    /// circuit does not support lookup.
803    fn check_range_gate(&self, idx: usize) -> Result<(), CircuitError> {
804        self.check_plonk_type(PlonkType::UltraPlonk)?;
805        if idx >= self.wire_variables[RANGE_WIRE_ID].len() {
806            return Err(IndexError);
807        }
808        let range_size = self.range_size()?;
809        if self.witness[self.wire_variables[RANGE_WIRE_ID][idx]] >= F::from(range_size as u32) {
810            return Err(GateCheckFailure(
811                idx,
812                format!(
813                    "Range gate failed: {} >= {}",
814                    self.witness[self.wire_variables[RANGE_WIRE_ID][idx]], range_size
815                ),
816            ));
817        }
818        Ok(())
819    }
820
821    fn is_finalized(&self) -> bool {
822        self.eval_domain.size() != 1
823    }
824
825    /// Re-arrange the order of the gates so that:
826    /// 1. io gates are in the front.
827    /// 2. variable table lookup gate are at the rear so that they do not affect
828    ///    the range gates when merging the lookup tables.
829    ///
830    /// Remember to pad gates before calling the method.
831    fn rearrange_gates(&mut self) -> Result<(), CircuitError> {
832        self.check_finalize_flag(true)?;
833        for (gate_id, io_gate_id) in self.pub_input_gate_ids.iter_mut().enumerate() {
834            if *io_gate_id > gate_id {
835                // Swap gate types
836                self.gates.swap(gate_id, *io_gate_id);
837                // Swap wire variables
838                for i in 0..GATE_WIDTH + 1 {
839                    self.wire_variables[i].swap(gate_id, *io_gate_id);
840                }
841                // Update io gate index
842                *io_gate_id = gate_id;
843            }
844        }
845        if self.support_lookup() {
846            // move lookup gates to the rear, the relative order of the lookup gates
847            // should not change
848            let n = self.eval_domain.size();
849            // be careful that we can't put a lookup gates at the very last slot.
850            let mut cur_gate_id = n - 2;
851            for &(table_gate_id, table_size) in self.table_gate_ids.iter().rev() {
852                for gate_id in (table_gate_id..table_gate_id + table_size).rev() {
853                    if gate_id < cur_gate_id {
854                        // Swap gate types
855                        self.gates.swap(gate_id, cur_gate_id);
856                        // Swap wire variables
857                        for j in 0..GATE_WIDTH + 1 {
858                            self.wire_variables[j].swap(gate_id, cur_gate_id);
859                        }
860                        cur_gate_id -= 1;
861                    }
862                }
863            }
864        }
865        Ok(())
866    }
867    // use downcast to check whether a gate is of IoGate type
868    fn is_io_gate(&self, gate_id: GateId) -> bool {
869        self.gates[gate_id].as_any().is::<IoGate>()
870    }
871
872    // pad a finalized circuit to match the evaluation domain, prepared for
873    // arithmetization.
874    fn pad(&mut self) -> Result<(), CircuitError> {
875        self.check_finalize_flag(true)?;
876        let n = self.eval_domain.size();
877        for _ in self.num_gates()..n {
878            self.gates.push(Box::new(PaddingGate));
879        }
880        for wire_id in 0..self.num_wire_types() {
881            self.wire_variables[wire_id].resize(n, self.zero());
882        }
883        Ok(())
884    }
885
886    /// Check that the `gate_id`-th gate is satisfied by the circuit's witness
887    /// and the public input value `pub_input`. `gate_id` is guaranteed to
888    /// be in the range. The gate equation:
889    /// qo * wo = pub_input + q_c +
890    ///           q_mul0 * w0 * w1 + q_mul1 * w2 * w3 +
891    ///           q_lc0 * w0 + q_lc1 * w1 + q_lc2 * w2 + q_lc3 * w3 +
892    ///           q_hash0 * w0 + q_hash1 * w1 + q_hash2 * w2 + q_hash3 * w3 +
893    ///           q_ecc * w0 * w1 * w2 * w3 * wo
894    fn check_gate(&self, gate_id: Variable, pub_input: &F) -> Result<(), CircuitError> {
895        // Compute wire values
896
897        let w_vals: Vec<F> = (0..GATE_WIDTH + 1)
898            .map(|i| self.witness[self.wire_variables[i][gate_id]])
899            .collect();
900        // Compute selector values.
901        let q_lc: [F; GATE_WIDTH] = self.gates[gate_id].q_lc();
902        let q_mul: [F; N_MUL_SELECTORS] = self.gates[gate_id].q_mul();
903        let q_hash: [F; GATE_WIDTH] = self.gates[gate_id].q_hash();
904        let q_c = self.gates[gate_id].q_c();
905        let q_o = self.gates[gate_id].q_o();
906        let q_ecc = self.gates[gate_id].q_ecc();
907
908        // Compute the gate output
909        let expected_gate_output = *pub_input
910            + q_lc[0] * w_vals[0]
911            + q_lc[1] * w_vals[1]
912            + q_lc[2] * w_vals[2]
913            + q_lc[3] * w_vals[3]
914            + q_mul[0] * w_vals[0] * w_vals[1]
915            + q_mul[1] * w_vals[2] * w_vals[3]
916            + q_ecc * w_vals[0] * w_vals[1] * w_vals[2] * w_vals[3] * w_vals[4]
917            + q_hash[0] * w_vals[0].pow([5])
918            + q_hash[1] * w_vals[1].pow([5])
919            + q_hash[2] * w_vals[2].pow([5])
920            + q_hash[3] * w_vals[3].pow([5])
921            + q_c;
922        let gate_output = q_o * w_vals[4];
923        if expected_gate_output != gate_output {
924            return Err(
925                GateCheckFailure(
926                    gate_id,
927                    format!(
928                        "gate: {:?}, wire values: {:?}, pub_input: {}, expected_gate_output: {}, gate_output: {}",
929                        self.gates[gate_id],
930                        w_vals,
931                        pub_input,
932                        expected_gate_output,
933                        gate_output
934                    )
935                ));
936        }
937        Ok(())
938    }
939
940    // Compute the permutation over wires.
941    // The circuit is guaranteed to be padded before calling the method.
942    #[inline]
943    fn compute_wire_permutation(&mut self) {
944        assert!(self.is_finalized());
945        let n = self.eval_domain.size();
946        let m = self.num_vars();
947
948        // Compute the mapping from variables to wires.
949        // NOTE: we can use a vector as a map because our variable (the intended "key"
950        // value type of the Map) is sorted and match exactly as the
951        // non-negative integer ranged from 0 to m. Our current implementation should be
952        // slightly faster than using a `HashMap<Variable, Vec<(WireId, GateId)>>` as we
953        // avoid any constant overhead from the hashmap read/write.
954        let mut variable_wires_map = vec![vec![]; m];
955        for (gate_wire_id, variables) in self
956            .wire_variables
957            .iter()
958            .take(self.num_wire_types())
959            .enumerate()
960        {
961            for (gate_id, &var) in variables.iter().enumerate() {
962                variable_wires_map[var].push((gate_wire_id, gate_id));
963            }
964        }
965
966        // Compute the wire permutation
967        self.wire_permutation = vec![(0usize, 0usize); self.num_wire_types * n];
968        for wires_vec in variable_wires_map.iter_mut() {
969            // The list of wires that map to the same variable forms a cycle.
970            if !wires_vec.is_empty() {
971                // push the first item so that window iterator will visit the last item
972                // paired with the first item, forming a cycle
973                wires_vec.push(wires_vec[0]);
974                for window in wires_vec.windows(2) {
975                    self.wire_permutation[window[0].0 * n + window[0].1] = window[1];
976                }
977                // remove the extra first item pushed at the beginning of the iterator
978                wires_vec.pop();
979            }
980        }
981    }
982
983    // Check whether the circuit is finalized. Return an error if the finalizing
984    // status is different from the expected status.
985    #[inline]
986    fn check_finalize_flag(&self, expect_finalized: bool) -> Result<(), CircuitError> {
987        if !self.is_finalized() && expect_finalized {
988            return Err(UnfinalizedCircuit);
989        }
990        if self.is_finalized() && !expect_finalized {
991            return Err(ModifyFinalizedCircuit);
992        }
993        Ok(())
994    }
995
996    // Check whether the Plonk type is the expected Plonk type. Return an error if
997    // not.
998    #[inline]
999    fn check_plonk_type(&self, expect_type: PlonkType) -> Result<(), CircuitError> {
1000        if self.plonk_params.plonk_type != expect_type {
1001            return Err(WrongPlonkType);
1002        }
1003        Ok(())
1004    }
1005
1006    // Return the variable that maps to a wire `(i, j)` where i is the wire type and
1007    // j is the gate index. If gate `j` is a padded dummy gate, return zero
1008    // variable.
1009    #[inline]
1010    fn wire_variable(&self, i: WireId, j: GateId) -> Variable {
1011        match j < self.wire_variables[i].len() {
1012            true => self.wire_variables[i][j],
1013            false => self.zero(),
1014        }
1015    }
1016
1017    // getter for all linear combination selector
1018    #[inline]
1019    fn q_lc(&self) -> [Vec<F>; GATE_WIDTH] {
1020        let mut result = [vec![], vec![], vec![], vec![]];
1021        for gate in &self.gates {
1022            let q_lc_vec = gate.q_lc();
1023            result[0].push(q_lc_vec[0]);
1024            result[1].push(q_lc_vec[1]);
1025            result[2].push(q_lc_vec[2]);
1026            result[3].push(q_lc_vec[3]);
1027        }
1028        result
1029    }
1030    // getter for all multiplication selector
1031    #[inline]
1032    fn q_mul(&self) -> [Vec<F>; N_MUL_SELECTORS] {
1033        let mut result = [vec![], vec![]];
1034        for gate in &self.gates {
1035            let q_mul_vec = gate.q_mul();
1036            result[0].push(q_mul_vec[0]);
1037            result[1].push(q_mul_vec[1]);
1038        }
1039        result
1040    }
1041    // getter for all hash selector
1042    #[inline]
1043    fn q_hash(&self) -> [Vec<F>; GATE_WIDTH] {
1044        let mut result = [vec![], vec![], vec![], vec![]];
1045        for gate in &self.gates {
1046            let q_hash_vec = gate.q_hash();
1047            result[0].push(q_hash_vec[0]);
1048            result[1].push(q_hash_vec[1]);
1049            result[2].push(q_hash_vec[2]);
1050            result[3].push(q_hash_vec[3]);
1051        }
1052        result
1053    }
1054    // getter for all output selector
1055    #[inline]
1056    fn q_o(&self) -> Vec<F> {
1057        self.gates.iter().map(|g| g.q_o()).collect()
1058    }
1059    // getter for all constant selector
1060    #[inline]
1061    fn q_c(&self) -> Vec<F> {
1062        self.gates.iter().map(|g| g.q_c()).collect()
1063    }
1064    // getter for all ecc selector
1065    #[inline]
1066    fn q_ecc(&self) -> Vec<F> {
1067        self.gates.iter().map(|g| g.q_ecc()).collect()
1068    }
1069    // getter for all lookup selector
1070    #[inline]
1071    fn q_lookup(&self) -> Vec<F> {
1072        self.gates.iter().map(|g| g.q_lookup()).collect()
1073    }
1074    // getter for all lookup domain separation selector
1075    #[inline]
1076    fn q_dom_sep(&self) -> Vec<F> {
1077        self.gates.iter().map(|g| g.q_dom_sep()).collect()
1078    }
1079    // getter for the vector of table keys
1080    #[inline]
1081    fn table_key_vec(&self) -> Vec<F> {
1082        self.gates.iter().map(|g| g.table_key()).collect()
1083    }
1084    // getter for the vector of table domain separation ids
1085    #[inline]
1086    fn table_dom_sep_vec(&self) -> Vec<F> {
1087        self.gates.iter().map(|g| g.table_dom_sep()).collect()
1088    }
1089    // TODO: (alex) try return reference instead of expensive clone
1090    // getter for all selectors in the following order:
1091    // q_lc, q_mul, q_hash, q_o, q_c, q_ecc, [q_lookup (if support lookup)]
1092    #[inline]
1093    fn all_selectors(&self) -> Vec<Vec<F>> {
1094        let mut selectors = vec![];
1095        self.q_lc()
1096            .as_ref()
1097            .iter()
1098            .chain(self.q_mul().as_ref().iter())
1099            .chain(self.q_hash().as_ref().iter())
1100            .for_each(|s| selectors.push(s.clone()));
1101        selectors.push(self.q_o());
1102        selectors.push(self.q_c());
1103        selectors.push(self.q_ecc());
1104        if self.support_lookup() {
1105            selectors.push(self.q_lookup());
1106        }
1107        selectors
1108    }
1109}
1110
1111/// Private permutation related methods
1112impl<F: PrimeField> PlonkCircuit<F> {
1113    /// Copy constraints: precompute the extended permutation over circuit
1114    /// wires. Refer to Sec 5.2 and Sec 8.1 of https://eprint.iacr.org/2019/953.pdf for more details.
1115    #[inline]
1116    fn compute_extended_id_permutation(&mut self) {
1117        assert!(self.is_finalized());
1118        let n = self.eval_domain.size();
1119
1120        // Compute the extended identity permutation
1121        // id[i*n+j] = k[i] * g^j
1122        let k: Vec<F> = compute_coset_representatives(self.num_wire_types, Some(n));
1123        // Precompute domain elements
1124        let group_elems: Vec<F> = self.eval_domain.elements().collect();
1125        // Compute extended identity permutation
1126        self.extended_id_permutation = vec![F::zero(); self.num_wire_types * n];
1127        for (i, &coset_repr) in k.iter().enumerate() {
1128            for (j, &group_elem) in group_elems.iter().enumerate() {
1129                self.extended_id_permutation[i * n + j] = coset_repr * group_elem;
1130            }
1131        }
1132    }
1133
1134    #[inline]
1135    fn compute_extended_permutation(&self) -> Result<Vec<F>, CircuitError> {
1136        assert!(self.is_finalized());
1137        let n = self.eval_domain.size();
1138
1139        // The extended wire permutation can be computed as
1140        // extended_perm[i] = id[wire_perm[i].into() * n + wire_perm[i].1]
1141        let extended_perm: Vec<F> = self
1142            .wire_permutation
1143            .iter()
1144            .map(|&(wire_id, gate_id)| {
1145                // if permutation value undefined, return 0
1146                if wire_id >= self.num_wire_types {
1147                    F::zero()
1148                } else {
1149                    self.extended_id_permutation[wire_id * n + gate_id]
1150                }
1151            })
1152            .collect();
1153        if extended_perm.len() != self.num_wire_types * n {
1154            return Err(ParameterError(
1155                "Length of the extended permutation vector should be number of gate \
1156                         (including padded dummy gates) * number of wire types"
1157                    .to_string(),
1158            ));
1159        }
1160        Ok(extended_perm)
1161    }
1162}
1163
1164/// Methods for finalizing and merging the circuits.
1165impl<F: PrimeField> PlonkCircuit<F> {
1166    /// Finalize the setup of the circuit before arithmetization.
1167    pub fn finalize_for_arithmetization(&mut self) -> Result<(), CircuitError> {
1168        if self.is_finalized() {
1169            return Ok(());
1170        }
1171        let num_slots_needed = match self.support_lookup() {
1172            false => self.num_gates(),
1173            true => max(
1174                self.num_gates(),
1175                max(self.range_size()?, self.wire_variables[RANGE_WIRE_ID].len())
1176                    + self.num_table_elems()
1177                    + 1,
1178            ), // range gates and lookup gates need to have separate slots
1179        };
1180        self.eval_domain = Radix2EvaluationDomain::new(num_slots_needed)
1181            .ok_or(CircuitError::DomainCreationError)?;
1182        self.pad()?;
1183        self.rearrange_gates()?;
1184        self.compute_wire_permutation();
1185        self.compute_extended_id_permutation();
1186        Ok(())
1187    }
1188
1189    /// Finalize the setup of a mergeable circuit.
1190    /// Two circuits can be merged only if they are with different circuit types
1191    /// The method only supports TurboPlonk circuits.
1192    pub fn finalize_for_mergeable_circuit(
1193        &mut self,
1194        circuit_type: MergeableCircuitType,
1195    ) -> Result<(), CircuitError> {
1196        if self.plonk_params.plonk_type != PlonkType::TurboPlonk {
1197            return Err(WrongPlonkType);
1198        }
1199        self.finalize_for_arithmetization()?;
1200        // double the domain size
1201        let n = self.eval_domain_size()?;
1202        self.eval_domain =
1203            Radix2EvaluationDomain::new(2 * n).ok_or(CircuitError::DomainCreationError)?;
1204        // pad dummy gates/wires in slots [n..2n)
1205        for _ in 0..n {
1206            self.gates.push(Box::new(PaddingGate));
1207        }
1208        for wire_id in 0..self.num_wire_types() {
1209            self.wire_variables[wire_id].resize(2 * n, self.zero());
1210        }
1211        if circuit_type == MergeableCircuitType::TypeA {
1212            // update wire permutation
1213            let mut wire_perm = vec![(self.num_wire_types, 0usize); self.num_wire_types * 2 * n];
1214            for i in 0..self.num_wire_types {
1215                for j in 0..n {
1216                    wire_perm[i * 2 * n + j] = self.wire_permutation[i * n + j];
1217                }
1218            }
1219            self.wire_permutation = wire_perm;
1220        } else {
1221            // reverse the gate indices.
1222            self.gates.reverse();
1223            for wire_id in 0..self.num_wire_types() {
1224                self.wire_variables[wire_id].reverse();
1225            }
1226            for io_gate in self.pub_input_gate_ids.iter_mut() {
1227                *io_gate = 2 * n - 1 - *io_gate;
1228            }
1229            // update wire_permutation
1230            let mut wire_perm = vec![(self.num_wire_types, 0usize); self.num_wire_types * 2 * n];
1231            for i in 0..self.num_wire_types {
1232                for j in 0..n {
1233                    let (wire_id, gate_id) = self.wire_permutation[i * n + j];
1234                    // the new gate index is the reverse of the original gate index
1235                    let gate_id = 2 * n - 1 - gate_id;
1236                    wire_perm[i * 2 * n + 2 * n - 1 - j] = (wire_id, gate_id);
1237                }
1238            }
1239            self.wire_permutation = wire_perm;
1240        }
1241        // need to recompute extended_id_permutation because the domain has changed.
1242        self.compute_extended_id_permutation();
1243        Ok(())
1244    }
1245
1246    /// Merge a type A circuit with a type B circuit.
1247    /// Both circuits should have been finalized before.
1248    /// The method only supports TurboPlonk circuits.
1249    #[allow(dead_code)]
1250    pub fn merge(&self, other: &Self) -> Result<Self, CircuitError> {
1251        self.check_finalize_flag(true)?;
1252        other.check_finalize_flag(true)?;
1253        if self.eval_domain_size()? != other.eval_domain_size()? {
1254            return Err(ParameterError(format!(
1255                "cannot merge circuits with different domain sizes: {}, {}",
1256                self.eval_domain_size()?,
1257                other.eval_domain_size()?
1258            )));
1259        }
1260        if self.plonk_params.plonk_type != PlonkType::TurboPlonk
1261            || other.plonk_params.plonk_type != PlonkType::TurboPlonk
1262        {
1263            return Err(ParameterError(
1264                "do not support merging non-TurboPlonk circuits.".to_string(),
1265            ));
1266        }
1267        if self.num_inputs() != other.num_inputs() {
1268            return Err(ParameterError(format!(
1269                "self.num_inputs = {} different from other.num_inputs = {}",
1270                self.num_inputs(),
1271                other.num_inputs()
1272            )));
1273        }
1274        if self.pub_input_gate_ids[0] != 0 {
1275            return Err(ParameterError(
1276                "the first circuit is not type A".to_string(),
1277            ));
1278        }
1279        if other.pub_input_gate_ids[0] != other.eval_domain_size()? - 1 {
1280            return Err(ParameterError(
1281                "the second circuit is not type B".to_string(),
1282            ));
1283        }
1284        let num_vars = self.num_vars + other.num_vars;
1285        let witness: Vec<F> = [self.witness.as_slice(), other.witness.as_slice()].concat();
1286        let pub_input_gate_ids: Vec<usize> = [
1287            self.pub_input_gate_ids.as_slice(),
1288            other.pub_input_gate_ids.as_slice(),
1289        ]
1290        .concat();
1291
1292        // merge gates and wire variables
1293        // the first circuit occupies the first n gates, the second circuit
1294        // occupies the last n gates.
1295        let n = self.eval_domain_size()? / 2;
1296        let mut gates = vec![];
1297        let mut wire_variables = [vec![], vec![], vec![], vec![], vec![], vec![]];
1298        for (j, gate) in self.gates.iter().take(n).enumerate() {
1299            gates.push((*gate).clone());
1300            for (i, wire_vars) in wire_variables
1301                .iter_mut()
1302                .enumerate()
1303                .take(self.num_wire_types)
1304            {
1305                wire_vars.push(self.wire_variable(i, j));
1306            }
1307        }
1308        for (j, gate) in other.gates.iter().skip(n).enumerate() {
1309            gates.push((*gate).clone());
1310            for (i, wire_vars) in wire_variables
1311                .iter_mut()
1312                .enumerate()
1313                .take(self.num_wire_types)
1314            {
1315                wire_vars.push(other.wire_variable(i, n + j) + self.num_vars);
1316            }
1317        }
1318
1319        // merge wire_permutation
1320        let mut wire_permutation = vec![(0usize, 0usize); self.num_wire_types * 2 * n];
1321        for i in 0..self.num_wire_types {
1322            for j in 0..n {
1323                wire_permutation[i * 2 * n + j] = self.wire_permutation[i * 2 * n + j];
1324                wire_permutation[i * 2 * n + n + j] = other.wire_permutation[i * 2 * n + n + j];
1325            }
1326        }
1327
1328        Ok(Self {
1329            num_vars,
1330            witness,
1331            gates,
1332            wire_variables,
1333            pub_input_gate_ids,
1334            wire_permutation,
1335            extended_id_permutation: self.extended_id_permutation.clone(),
1336            num_wire_types: self.num_wire_types,
1337            eval_domain: self.eval_domain,
1338            plonk_params: self.plonk_params,
1339            num_table_elems: 0,
1340            table_gate_ids: vec![],
1341        })
1342    }
1343}
1344
1345impl<F> Arithmetization<F> for PlonkCircuit<F>
1346where
1347    F: PrimeField,
1348{
1349    fn srs_size(&self) -> Result<usize, CircuitError> {
1350        // extra 2 degree for masking polynomial to make snark zero-knowledge
1351        Ok(self.eval_domain_size()? + 2)
1352    }
1353
1354    fn eval_domain_size(&self) -> Result<usize, CircuitError> {
1355        self.check_finalize_flag(true)?;
1356        Ok(self.eval_domain.size())
1357    }
1358
1359    fn compute_selector_polynomials(&self) -> Result<Vec<DensePolynomial<F>>, CircuitError> {
1360        self.check_finalize_flag(true)?;
1361        let domain = &self.eval_domain;
1362        if domain.size() < self.num_gates() {
1363            return Err(ParameterError(
1364                "Domain size should be bigger than number of constraint".to_string(),
1365            ));
1366        }
1367        // order: (lc, mul, hash, o, c, ecc) as specified in spec
1368        let selector_polys = parallelizable_slice_iter(&self.all_selectors())
1369            .map(|selector| DensePolynomial::from_coefficients_vec(domain.ifft(selector)))
1370            .collect();
1371        Ok(selector_polys)
1372    }
1373
1374    fn compute_extended_permutation_polynomials(
1375        &self,
1376    ) -> Result<Vec<DensePolynomial<F>>, CircuitError> {
1377        self.check_finalize_flag(true)?;
1378        let domain = &self.eval_domain;
1379        let n = domain.size();
1380        let extended_perm = self.compute_extended_permutation()?;
1381
1382        let extended_perm_polys: Vec<DensePolynomial<F>> =
1383            parallelizable_slice_iter(&(0..self.num_wire_types).collect::<Vec<_>>()) // current par_utils only support slice iterator, not range iterator.
1384                .map(|i| {
1385                    DensePolynomial::from_coefficients_vec(
1386                        domain.ifft(&extended_perm[i * n..(i + 1) * n]),
1387                    )
1388                })
1389                .collect();
1390
1391        Ok(extended_perm_polys)
1392    }
1393
1394    fn compute_prod_permutation_polynomial(
1395        &self,
1396        beta: &F,
1397        gamma: &F,
1398    ) -> Result<DensePolynomial<F>, CircuitError> {
1399        self.check_finalize_flag(true)?;
1400        let mut product_vec = vec![F::one()];
1401        let domain = &self.eval_domain;
1402        let n = domain.size();
1403        for j in 0..(n - 1) {
1404            // Nominator
1405            let mut a = F::one();
1406            // Denominator
1407            let mut b = F::one();
1408            for i in 0..self.num_wire_types {
1409                let wire_value = self.witness[self.wire_variable(i, j)];
1410                let tmp = wire_value + gamma;
1411                a *= tmp + *beta * self.extended_id_permutation[i * n + j];
1412                let (perm_i, perm_j) = self.wire_permutation[i * n + j];
1413                b *= tmp + *beta * self.extended_id_permutation[perm_i * n + perm_j];
1414            }
1415            let prev_prod = *product_vec.last().ok_or(CircuitError::IndexError)?;
1416            product_vec.push(prev_prod * a / b);
1417        }
1418        domain.ifft_in_place(&mut product_vec);
1419        Ok(DensePolynomial::from_coefficients_vec(product_vec))
1420    }
1421
1422    fn compute_wire_polynomials(&self) -> Result<Vec<DensePolynomial<F>>, CircuitError> {
1423        self.check_finalize_flag(true)?;
1424        let domain = &self.eval_domain;
1425        if domain.size() < self.num_gates() {
1426            return Err(ParameterError(format!(
1427                "Domain size {} should be bigger than number of constraint {}",
1428                domain.size(),
1429                self.num_gates()
1430            )));
1431        }
1432        let witness = &self.witness;
1433        let wire_polys: Vec<DensePolynomial<F>> = parallelizable_slice_iter(&self.wire_variables)
1434            .take(self.num_wire_types())
1435            .map(|wire_vars| {
1436                let mut wire_vec: Vec<F> = wire_vars.iter().map(|&var| witness[var]).collect();
1437                domain.ifft_in_place(&mut wire_vec);
1438                DensePolynomial::from_coefficients_vec(wire_vec)
1439            })
1440            .collect();
1441
1442        assert_eq!(wire_polys.len(), self.num_wire_types());
1443        Ok(wire_polys)
1444    }
1445
1446    fn compute_pub_input_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
1447        self.check_finalize_flag(true)?;
1448        let domain = &self.eval_domain;
1449        let mut pub_input_vec = vec![F::zero(); domain.size()];
1450        self.pub_input_gate_ids.iter().for_each(|&io_gate_id| {
1451            let var = self.wire_variables[GATE_WIDTH][io_gate_id];
1452            pub_input_vec[io_gate_id] = self.witness[var];
1453        });
1454        domain.ifft_in_place(&mut pub_input_vec);
1455        Ok(DensePolynomial::from_coefficients_vec(pub_input_vec))
1456    }
1457
1458    // Plookup-related methods
1459    //
1460    fn compute_range_table_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
1461        let range_table = self.compute_range_table()?;
1462        let domain = &self.eval_domain;
1463        Ok(DensePolynomial::from_coefficients_vec(
1464            domain.ifft(&range_table),
1465        ))
1466    }
1467
1468    fn compute_key_table_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
1469        self.check_plonk_type(PlonkType::UltraPlonk)?;
1470        self.check_finalize_flag(true)?;
1471        let domain = &self.eval_domain;
1472        Ok(DensePolynomial::from_coefficients_vec(
1473            domain.ifft(&self.table_key_vec()),
1474        ))
1475    }
1476
1477    fn compute_table_dom_sep_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
1478        self.check_plonk_type(PlonkType::UltraPlonk)?;
1479        self.check_finalize_flag(true)?;
1480        let domain = &self.eval_domain;
1481        Ok(DensePolynomial::from_coefficients_vec(
1482            domain.ifft(&self.table_dom_sep_vec()),
1483        ))
1484    }
1485
1486    fn compute_q_dom_sep_polynomial(&self) -> Result<DensePolynomial<F>, CircuitError> {
1487        self.check_plonk_type(PlonkType::UltraPlonk)?;
1488        self.check_finalize_flag(true)?;
1489        let domain = &self.eval_domain;
1490        Ok(DensePolynomial::from_coefficients_vec(
1491            domain.ifft(&self.q_dom_sep()),
1492        ))
1493    }
1494
1495    fn compute_merged_lookup_table(&self, tau: F) -> Result<Vec<F>, CircuitError> {
1496        let range_table = self.compute_range_table()?;
1497        let table_key_vec = self.table_key_vec();
1498        let table_dom_sep_vec = self.table_dom_sep_vec();
1499        let q_lookup_vec = self.q_lookup();
1500
1501        let mut merged_lookup_table = vec![];
1502        for i in 0..self.eval_domain_size()? {
1503            merged_lookup_table.push(self.merged_table_value(
1504                tau,
1505                &range_table,
1506                &table_key_vec,
1507                &table_dom_sep_vec,
1508                &q_lookup_vec,
1509                i,
1510            )?);
1511        }
1512
1513        Ok(merged_lookup_table)
1514    }
1515
1516    fn compute_lookup_prod_polynomial(
1517        &self,
1518        tau: &F,
1519        beta: &F,
1520        gamma: &F,
1521        merged_lookup_table: &[F],
1522        sorted_vec: &[F],
1523    ) -> Result<DensePolynomial<F>, CircuitError> {
1524        self.check_plonk_type(PlonkType::UltraPlonk)?;
1525        self.check_finalize_flag(true)?;
1526        let domain = &self.eval_domain;
1527        let n = domain.size();
1528        if n != self.wire_variables[RANGE_WIRE_ID].len() {
1529            return Err(ParameterError(
1530                "Domain size should match the size of the padded lookup variables vector"
1531                    .to_string(),
1532            ));
1533        }
1534        if n != merged_lookup_table.len() {
1535            return Err(ParameterError(
1536                "Domain size should match the size of the padded lookup table".to_string(),
1537            ));
1538        }
1539        if 2 * n - 1 != sorted_vec.len() {
1540            return Err(ParameterError(
1541                "The sorted vector has wrong length".to_string(),
1542            ));
1543        }
1544
1545        let mut product_vec = vec![F::one()];
1546        let beta_plus_one = F::one() + *beta;
1547        let gamma_mul_beta_plus_one = *gamma * beta_plus_one;
1548        let q_lookup_vec = self.q_lookup();
1549        let q_dom_sep_vec = self.q_dom_sep();
1550        for j in 0..(n - 2) {
1551            // compute merged lookup witness value
1552            let lookup_wire_val =
1553                self.merged_lookup_wire_value(*tau, j, &q_lookup_vec, &q_dom_sep_vec)?;
1554            let table_val = merged_lookup_table[j];
1555            let table_next_val = merged_lookup_table[j + 1];
1556            let h1_val = sorted_vec[j];
1557            let h1_next_val = sorted_vec[j + 1];
1558            let h2_val = sorted_vec[n - 1 + j];
1559            let h2_next_val = sorted_vec[n + j];
1560
1561            // Nominator
1562            let a = beta_plus_one
1563                * (*gamma + lookup_wire_val)
1564                * (gamma_mul_beta_plus_one + table_val + *beta * table_next_val);
1565            // Denominator
1566            let b = (gamma_mul_beta_plus_one + h1_val + *beta * h1_next_val)
1567                * (gamma_mul_beta_plus_one + h2_val + *beta * h2_next_val);
1568
1569            let prev_prod = *product_vec.last().ok_or(CircuitError::IndexError)?;
1570            product_vec.push(prev_prod * a / b);
1571        }
1572        product_vec.push(F::one());
1573        domain.ifft_in_place(&mut product_vec);
1574        Ok(DensePolynomial::from_coefficients_vec(product_vec))
1575    }
1576
1577    fn compute_lookup_sorted_vec_polynomials(
1578        &self,
1579        tau: F,
1580        merged_lookup_table: &[F],
1581    ) -> Result<SortedLookupVecAndPolys<F>, CircuitError> {
1582        self.check_plonk_type(PlonkType::UltraPlonk)?;
1583        self.check_finalize_flag(true)?;
1584        let domain = &self.eval_domain;
1585        let n = domain.size();
1586        if n != self.wire_variables[RANGE_WIRE_ID].len() {
1587            return Err(ParameterError(
1588                "Domain size should match the size of the padded lookup variables vector"
1589                    .to_string(),
1590            ));
1591        }
1592        if n != merged_lookup_table.len() {
1593            return Err(ParameterError(
1594                "Domain size should match the size of the padded lookup table".to_string(),
1595            ));
1596        }
1597        // only the first n-1 variables are for lookup
1598        let mut lookup_map = HashMap::<F, usize>::new();
1599        let q_lookup_vec = self.q_lookup();
1600        let q_dom_sep_vec = self.q_dom_sep();
1601        for i in 0..(n - 1) {
1602            let elem = self.merged_lookup_wire_value(tau, i, &q_lookup_vec, &q_dom_sep_vec)?;
1603            let n_lookups = lookup_map.entry(elem).or_insert(0);
1604            *n_lookups += 1;
1605        }
1606        // merge-sort the lookup vector with the (merged) lookup table
1607        // according to the order of the (merged) lookup table.
1608        let mut sorted_vec = vec![];
1609        for elem in merged_lookup_table.iter() {
1610            if let Some(n_lookup) = lookup_map.get(elem) {
1611                sorted_vec.extend(vec![*elem; 1 + n_lookup]);
1612                lookup_map.remove(elem);
1613            } else {
1614                sorted_vec.push(*elem);
1615            }
1616        }
1617
1618        if sorted_vec.len() != 2 * n - 1 {
1619            return Err(ParameterError("The sorted vector has wrong length, some lookup variables might be outside the table".to_string()));
1620        }
1621        let h1_poly = DensePolynomial::from_coefficients_vec(domain.ifft(&sorted_vec[..n]));
1622        let h2_poly = DensePolynomial::from_coefficients_vec(domain.ifft(&sorted_vec[n - 1..]));
1623        Ok((sorted_vec, h1_poly, h2_poly))
1624    }
1625}
1626
1627/// Private helper methods for arithmetizations.
1628impl<F: PrimeField> PlonkCircuit<F> {
1629    #[inline]
1630    fn compute_range_table(&self) -> Result<Vec<F>, CircuitError> {
1631        self.check_plonk_type(PlonkType::UltraPlonk)?;
1632        self.check_finalize_flag(true)?;
1633        let domain = &self.eval_domain;
1634        let range_size = self.range_size()?;
1635        if domain.size() < range_size {
1636            return Err(ParameterError(format!(
1637                "Domain size {} < range size {}",
1638                domain.size(),
1639                range_size
1640            )));
1641        }
1642        let mut range_table: Vec<F> = (0..range_size).map(|i| F::from(i as u32)).collect();
1643        range_table.resize(domain.size(), F::zero());
1644        Ok(range_table)
1645    }
1646
1647    #[inline]
1648    fn merged_table_value(
1649        &self,
1650        tau: F,
1651        range_table: &[F],
1652        table_key_vec: &[F],
1653        table_dom_sep_vec: &[F],
1654        q_lookup_vec: &[F],
1655        i: usize,
1656    ) -> Result<F, CircuitError> {
1657        let range_val = range_table[i];
1658        let key_val = table_key_vec[i];
1659        let dom_sep_val = table_dom_sep_vec[i];
1660        let q_lookup_val = q_lookup_vec[i];
1661        let table_val_1 = self.witness(self.wire_variable(TABLE_VAL_1_WIRE_ID, i))?;
1662        let table_val_2 = self.witness(self.wire_variable(TABLE_VAL_2_WIRE_ID, i))?;
1663        Ok(range_val
1664            + q_lookup_val
1665                * tau
1666                * (dom_sep_val + tau * (key_val + tau * (table_val_1 + tau * table_val_2))))
1667    }
1668
1669    #[inline]
1670    fn merged_lookup_wire_value(
1671        &self,
1672        tau: F,
1673        i: usize,
1674        q_lookup_vec: &[F],
1675        q_dom_sep_vec: &[F],
1676    ) -> Result<F, CircuitError> {
1677        let w_range_val = self.witness(self.wire_variable(RANGE_WIRE_ID, i))?;
1678        let lookup_key = self.witness(self.wire_variable(LOOKUP_KEY_WIRE_ID, i))?;
1679        let lookup_val_1 = self.witness(self.wire_variable(LOOKUP_VAL_1_WIRE_ID, i))?;
1680        let lookup_val_2 = self.witness(self.wire_variable(LOOKUP_VAL_2_WIRE_ID, i))?;
1681        let q_lookup_val = q_lookup_vec[i];
1682        let q_dom_sep_val = q_dom_sep_vec[i];
1683        Ok(w_range_val
1684            + q_lookup_val
1685                * tau
1686                * (q_dom_sep_val + tau * (lookup_key + tau * (lookup_val_1 + tau * lookup_val_2))))
1687    }
1688}
1689
1690#[cfg(test)]
1691pub(crate) mod test {
1692    use super::{Arithmetization, Circuit, PlonkCircuit};
1693    use crate::{constants::compute_coset_representatives, CircuitError};
1694    use ark_bls12_377::Fq as Fq377;
1695    use ark_ed_on_bls12_377::Fq as FqEd377;
1696    use ark_ed_on_bls12_381::Fq as FqEd381;
1697    use ark_ed_on_bn254::Fq as FqEd254;
1698    use ark_ff::PrimeField;
1699    use ark_poly::{domain::Radix2EvaluationDomain, univariate::DensePolynomial, EvaluationDomain};
1700    use ark_std::{vec, vec::Vec};
1701    use jf_utils::test_rng;
1702
1703    #[test]
1704    fn test_circuit_trait() -> Result<(), CircuitError> {
1705        test_circuit_trait_helper::<FqEd254>()?;
1706        test_circuit_trait_helper::<FqEd377>()?;
1707        test_circuit_trait_helper::<FqEd381>()?;
1708        test_circuit_trait_helper::<Fq377>()
1709    }
1710
1711    fn test_circuit_trait_helper<F: PrimeField>() -> Result<(), CircuitError> {
1712        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1713        // Create secret variables.
1714        let a = circuit.create_variable(F::from(3u32))?;
1715        let b = circuit.create_variable(F::from(1u32))?;
1716        // Constant gate: a = 3.
1717        circuit.enforce_constant(a, F::from(3u32))?;
1718        // Bool gate: b is bool.
1719        circuit.enforce_bool(b)?;
1720        // Addition gate: c = a + b = 4.
1721        let c = circuit.add(a, b)?;
1722        // Subtraction gate: d = a - b = 2.
1723        let d = circuit.sub(a, b)?;
1724        // Multiplication gate: e = c * d = 8
1725        let e = circuit.mul(c, d)?;
1726        // Create public variables.
1727        let f = circuit.create_public_variable(F::from(8u32))?;
1728        // Equality gate: e = f = 8
1729        circuit.enforce_equal(e, f)?;
1730
1731        // Check the number of gates:
1732        // 2 constant gates for default 0/1, 6 arithmetic gates, 1 io gate.
1733        assert_eq!(circuit.num_gates(), 9);
1734        // Check the number of variables:
1735        assert_eq!(circuit.num_vars(), 8);
1736        // Check the number of public inputs:
1737        assert_eq!(circuit.num_inputs(), 1);
1738
1739        // Check circuit satisfiability
1740        let pub_input = &[F::from(8u32)];
1741        let verify = circuit.check_circuit_satisfiability(pub_input);
1742        assert!(verify.is_ok(), "{:?}", verify.unwrap_err());
1743        let bad_pub_input = &[F::from(0u32)];
1744        assert!(circuit.check_circuit_satisfiability(bad_pub_input).is_err());
1745        // Wrong public input length
1746        let bad_pub_input = &[F::from(8u32), F::from(8u32)];
1747        assert!(circuit.check_circuit_satisfiability(bad_pub_input).is_err());
1748
1749        Ok(())
1750    }
1751
1752    #[test]
1753    fn test_add() -> Result<(), CircuitError> {
1754        test_add_helper::<FqEd254>()?;
1755        test_add_helper::<FqEd377>()?;
1756        test_add_helper::<FqEd381>()?;
1757        test_add_helper::<Fq377>()
1758    }
1759
1760    fn test_add_helper<F: PrimeField>() -> Result<(), CircuitError> {
1761        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1762        let a = circuit.create_variable(F::from(3u32))?;
1763        let b = circuit.create_variable(F::from(1u32))?;
1764        let c = circuit.add(a, b)?;
1765
1766        // Check circuits.
1767        assert_eq!(circuit.witness(c)?, F::from(4u32));
1768        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
1769        *circuit.witness_mut(c) = F::from(1u32);
1770        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
1771
1772        // Check variable out of bound error.
1773        assert!(circuit.add(circuit.num_vars(), a).is_err());
1774
1775        Ok(())
1776    }
1777
1778    #[test]
1779    fn test_sub() -> Result<(), CircuitError> {
1780        test_sub_helper::<FqEd254>()?;
1781        test_sub_helper::<FqEd377>()?;
1782        test_sub_helper::<FqEd381>()?;
1783        test_sub_helper::<Fq377>()
1784    }
1785
1786    fn test_sub_helper<F: PrimeField>() -> Result<(), CircuitError> {
1787        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1788        let a = circuit.create_variable(F::from(3u32))?;
1789        let b = circuit.create_variable(F::from(1u32))?;
1790        let c = circuit.sub(a, b)?;
1791
1792        // Check circuits.
1793        assert_eq!(circuit.witness(c)?, F::from(2u32));
1794        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
1795        *circuit.witness_mut(c) = F::from(1u32);
1796        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
1797
1798        // Check variable out of bound error.
1799        assert!(circuit.sub(circuit.num_vars(), a).is_err());
1800
1801        Ok(())
1802    }
1803
1804    #[test]
1805    fn test_mul() -> Result<(), CircuitError> {
1806        test_mul_helper::<FqEd254>()?;
1807        test_mul_helper::<FqEd377>()?;
1808        test_mul_helper::<FqEd381>()?;
1809        test_mul_helper::<Fq377>()
1810    }
1811
1812    fn test_mul_helper<F: PrimeField>() -> Result<(), CircuitError> {
1813        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1814        let a = circuit.create_variable(F::from(3u32))?;
1815        let b = circuit.create_variable(F::from(2u32))?;
1816        let c = circuit.mul(a, b)?;
1817
1818        // Check circuits.
1819        assert_eq!(circuit.witness(c)?, F::from(6u32));
1820        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
1821        *circuit.witness_mut(c) = F::from(1u32);
1822        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
1823
1824        // Check variable out of bound error.
1825        assert!(circuit.mul(circuit.num_vars(), a).is_err());
1826
1827        Ok(())
1828    }
1829
1830    #[test]
1831    fn test_equal_gate() -> Result<(), CircuitError> {
1832        test_equal_gate_helper::<FqEd254>()?;
1833        test_equal_gate_helper::<FqEd377>()?;
1834        test_equal_gate_helper::<FqEd381>()?;
1835        test_equal_gate_helper::<Fq377>()
1836    }
1837    fn test_equal_gate_helper<F: PrimeField>() -> Result<(), CircuitError> {
1838        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1839        let a = circuit.create_variable(F::from(3u32))?;
1840        let b = circuit.create_variable(F::from(3u32))?;
1841        circuit.enforce_equal(a, b)?;
1842
1843        // Check circuits.
1844        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
1845        *circuit.witness_mut(b) = F::from(1u32);
1846        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
1847
1848        // Check variable out of bound error.
1849        assert!(circuit.enforce_equal(circuit.num_vars(), a).is_err());
1850
1851        Ok(())
1852    }
1853
1854    #[test]
1855    fn test_bool() -> Result<(), CircuitError> {
1856        test_bool_helper::<FqEd254>()?;
1857        test_bool_helper::<FqEd377>()?;
1858        test_bool_helper::<FqEd381>()?;
1859        test_bool_helper::<Fq377>()
1860    }
1861
1862    fn test_bool_helper<F: PrimeField>() -> Result<(), CircuitError> {
1863        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1864        let a = circuit.create_variable(F::from(0u32))?;
1865        circuit.enforce_bool(a)?;
1866
1867        // Check circuits.
1868        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
1869        *circuit.witness_mut(a) = F::from(2u32);
1870        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
1871
1872        // Check variable out of bound error.
1873        assert!(circuit.enforce_bool(circuit.num_vars()).is_err());
1874
1875        Ok(())
1876    }
1877
1878    #[test]
1879    fn test_constant() -> Result<(), CircuitError> {
1880        test_constant_helper::<FqEd254>()?;
1881        test_constant_helper::<FqEd377>()?;
1882        test_constant_helper::<FqEd381>()?;
1883        test_constant_helper::<Fq377>()
1884    }
1885    fn test_constant_helper<F: PrimeField>() -> Result<(), CircuitError> {
1886        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1887        let a = circuit.create_variable(F::from(10u32))?;
1888        circuit.enforce_constant(a, F::from(10u32))?;
1889
1890        // Check circuits.
1891        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
1892        *circuit.witness_mut(a) = F::from(2u32);
1893        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
1894
1895        // Check variable out of bound error.
1896        assert!(circuit
1897            .enforce_constant(circuit.num_vars(), F::from(0u32))
1898            .is_err());
1899
1900        Ok(())
1901    }
1902
1903    #[test]
1904    fn test_io_gate() -> Result<(), CircuitError> {
1905        test_io_gate_helper::<FqEd254>()?;
1906        test_io_gate_helper::<FqEd377>()?;
1907        test_io_gate_helper::<FqEd381>()?;
1908        test_io_gate_helper::<Fq377>()
1909    }
1910
1911    fn test_io_gate_helper<F: PrimeField>() -> Result<(), CircuitError> {
1912        let mut circuit = PlonkCircuit::<F>::new_turbo_plonk();
1913        let b = circuit.create_variable(F::from(0u32))?;
1914        let a = circuit.create_public_variable(F::from(1u32))?;
1915        circuit.enforce_bool(a)?;
1916        circuit.enforce_bool(b)?;
1917        circuit.set_variable_public(b)?;
1918
1919        // Different valid public inputs should all pass the circuit check.
1920        assert!(circuit
1921            .check_circuit_satisfiability(&[F::from(1u32), F::from(0u32)])
1922            .is_ok());
1923        *circuit.witness_mut(a) = F::from(0u32);
1924        assert!(circuit
1925            .check_circuit_satisfiability(&[F::from(0u32), F::from(0u32)])
1926            .is_ok());
1927        *circuit.witness_mut(b) = F::from(1u32);
1928        assert!(circuit
1929            .check_circuit_satisfiability(&[F::from(0u32), F::from(1u32)])
1930            .is_ok());
1931
1932        // Invalid public inputs should fail the circuit check.
1933        assert!(circuit
1934            .check_circuit_satisfiability(&[F::from(2u32), F::from(1u32)])
1935            .is_err());
1936        *circuit.witness_mut(a) = F::from(2u32);
1937        assert!(circuit
1938            .check_circuit_satisfiability(&[F::from(2u32), F::from(1u32)])
1939            .is_err());
1940        *circuit.witness_mut(a) = F::from(0u32);
1941        assert!(circuit
1942            .check_circuit_satisfiability(&[F::from(0u32), F::from(2u32)])
1943            .is_err());
1944        *circuit.witness_mut(b) = F::from(2u32);
1945        assert!(circuit
1946            .check_circuit_satisfiability(&[F::from(0u32), F::from(2u32)])
1947            .is_err());
1948
1949        Ok(())
1950    }
1951
1952    #[test]
1953    fn test_io_gate_multi_inputs() -> Result<(), CircuitError> {
1954        test_io_gate_multi_inputs_helper::<FqEd254>()?;
1955        test_io_gate_multi_inputs_helper::<FqEd377>()?;
1956        test_io_gate_multi_inputs_helper::<FqEd381>()?;
1957        test_io_gate_multi_inputs_helper::<Fq377>()
1958    }
1959    fn test_io_gate_multi_inputs_helper<F: PrimeField>() -> Result<(), CircuitError> {
1960        let mut circuit = PlonkCircuit::<F>::new_turbo_plonk();
1961        let a = circuit.create_public_variable(F::from(1u32))?;
1962        let b = circuit.create_public_variable(F::from(2u32))?;
1963        let c = circuit.create_public_variable(F::from(3u32))?;
1964        circuit.add_gate(a, b, c)?;
1965
1966        // Good path
1967        assert!(circuit
1968            .check_circuit_satisfiability(&[F::from(1u32), F::from(2u32), F::from(3u32)])
1969            .is_ok());
1970        // The circuit check should fail given a public input with wrong order.
1971        assert!(circuit
1972            .check_circuit_satisfiability(&[F::from(2u32), F::from(1u32), F::from(3u32)])
1973            .is_err());
1974        // A different valid public input should pass the circuit check.
1975        *circuit.witness_mut(a) = F::from(4u32);
1976        *circuit.witness_mut(b) = F::from(8u32);
1977        *circuit.witness_mut(c) = F::from(12u32);
1978        assert!(circuit
1979            .check_circuit_satisfiability(&[F::from(4u32), F::from(8u32), F::from(12u32)])
1980            .is_ok());
1981        // An invalid public input should fail the circuit check.
1982        *circuit.witness_mut(a) = F::from(2u32);
1983        assert!(circuit
1984            .check_circuit_satisfiability(&[F::from(2u32), F::from(8u32), F::from(12u32)])
1985            .is_err());
1986
1987        Ok(())
1988    }
1989
1990    fn create_turbo_plonk_instance<F: PrimeField>(
1991    ) -> Result<(PlonkCircuit<F>, Vec<F>), CircuitError> {
1992        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
1993        let a = circuit.create_variable(F::from(3u32))?;
1994        let b = circuit.create_public_variable(F::from(1u32))?;
1995        circuit.enforce_constant(a, F::from(3u32))?;
1996        circuit.enforce_bool(b)?;
1997        let c = circuit.add(a, b)?;
1998        let d = circuit.sub(a, b)?;
1999        let e = circuit.mul(c, d)?;
2000        let f = circuit.create_public_variable(F::from(8u32))?;
2001        circuit.enforce_equal(e, f)?;
2002
2003        Ok((circuit, vec![F::from(1u32), F::from(8u32)]))
2004    }
2005
2006    fn create_ultra_plonk_instance<F: PrimeField>(
2007    ) -> Result<(PlonkCircuit<F>, Vec<F>), CircuitError> {
2008        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_ultra_plonk(4);
2009        let a = circuit.create_variable(F::from(3u32))?;
2010        let b = circuit.create_public_variable(F::from(1u32))?;
2011        circuit.enforce_constant(a, F::from(3u32))?;
2012        circuit.enforce_bool(b)?;
2013        let c = circuit.add(a, b)?;
2014        let d = circuit.sub(a, b)?;
2015        let e = circuit.mul(c, d)?;
2016        let f = circuit.create_public_variable(F::from(8u32))?;
2017        circuit.enforce_equal(e, f)?;
2018
2019        // Add range gates
2020        circuit.add_range_check_variable(b)?;
2021        circuit.add_range_check_variable(c)?;
2022        circuit.add_range_check_variable(e)?;
2023        circuit.add_range_check_variable(f)?;
2024        circuit.add_range_check_variable(circuit.zero())?;
2025
2026        // Add variable table lookup gates
2027        // table = [(3,1), (4,2), (8,8)]
2028        let table_vars = [(a, b), (c, d), (e, f)];
2029        // lookup_witness = [(0, 3, 1), (2, 8, 8)]
2030        let x = circuit.create_variable(F::from(3u8))?;
2031        let y = circuit.create_variable(F::from(8u8))?;
2032        let key1 = circuit.create_variable(F::from(2u8))?;
2033        let lookup_vars = [(circuit.zero(), x, circuit.one()), (key1, y, y)];
2034        circuit.create_table_and_lookup_variables(&lookup_vars, &table_vars)?;
2035
2036        Ok((circuit, vec![F::from(1u32), F::from(8u32)]))
2037    }
2038
2039    /// Tests related to permutations
2040    #[test]
2041    fn test_compute_extended_permutation() -> Result<(), CircuitError> {
2042        test_compute_extended_permutation_helper::<FqEd254>()?;
2043        test_compute_extended_permutation_helper::<FqEd377>()?;
2044        test_compute_extended_permutation_helper::<FqEd381>()?;
2045        test_compute_extended_permutation_helper::<Fq377>()
2046    }
2047
2048    fn test_compute_extended_permutation_helper<F: PrimeField>() -> Result<(), CircuitError> {
2049        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
2050        let a = circuit.create_variable(F::from(2u32))?;
2051        let b = circuit.create_public_variable(F::from(3u32))?;
2052        let c = circuit.add(a, b)?;
2053        let d = circuit.add(circuit.one(), a)?;
2054        let _ = circuit.mul(c, d)?;
2055
2056        // Create a UltraPlonk instance
2057        let (mut circuit, _) = create_ultra_plonk_instance::<F>()?;
2058        check_wire_permutation_and_extended_id_permutation(&mut circuit)?;
2059
2060        Ok(())
2061    }
2062
2063    fn check_wire_permutation_and_extended_id_permutation<F: PrimeField>(
2064        circuit: &mut PlonkCircuit<F>,
2065    ) -> Result<(), CircuitError> {
2066        let domain = Radix2EvaluationDomain::<F>::new(circuit.num_gates())
2067            .ok_or(CircuitError::DomainCreationError)?;
2068        let n = domain.size();
2069        circuit.eval_domain = domain;
2070
2071        // Check wire permutation's correctness
2072        circuit.pad()?;
2073        circuit.compute_wire_permutation();
2074        let mut visit_wire = vec![false; circuit.num_wire_types * n];
2075        let mut visit_variable = vec![false; circuit.num_vars()];
2076
2077        for i in 0..circuit.num_wire_types {
2078            for j in 0..n {
2079                if visit_wire[i * n + j] {
2080                    continue;
2081                }
2082                // Compute the cycle's variable.
2083                let cycle_var = circuit.wire_variable(i, j);
2084                // The variable shouldn't have been marked yet.
2085                assert!(!visit_variable[cycle_var]);
2086                visit_variable[cycle_var] = true;
2087
2088                // Visit the cycle.
2089                let mut wire_id = i;
2090                let mut gate_id = j;
2091                visit_wire[i * n + j] = true;
2092                loop {
2093                    let (next_wire_id, next_gate_id) =
2094                        circuit.wire_permutation[wire_id * n + gate_id];
2095                    // Break the loop if back to the starting wire.
2096                    if next_wire_id == i && next_gate_id == j {
2097                        break;
2098                    }
2099                    let next_var = circuit.wire_variable(next_wire_id, next_gate_id);
2100                    // The adjacent wire's variable should be the same.
2101                    assert_eq!(cycle_var, next_var);
2102                    // The adjacent wire shouldn't have been marked yet.
2103                    assert!(!visit_wire[next_wire_id * n + next_gate_id]);
2104                    visit_wire[next_wire_id * n + next_gate_id] = true;
2105                    wire_id = next_wire_id;
2106                    gate_id = next_gate_id;
2107                }
2108            }
2109        }
2110
2111        // Check the correctness of the extended id permutation
2112        circuit.compute_extended_id_permutation();
2113        // Compute quadratic non-residues and group elements.
2114        let k: Vec<F> = compute_coset_representatives(circuit.num_wire_types, Some(n));
2115        let group_elems: Vec<F> = domain.elements().collect();
2116        (0..circuit.num_wire_types).for_each(|i| {
2117            (0..n).for_each(|j| {
2118                assert_eq!(
2119                    k[i] * group_elems[j],
2120                    circuit.extended_id_permutation[i * n + j]
2121                )
2122            });
2123        });
2124
2125        Ok(())
2126    }
2127
2128    // Test flags
2129    //
2130
2131    #[test]
2132    fn test_ultra_plonk_flag() -> Result<(), CircuitError> {
2133        test_ultra_plonk_flag_helper::<FqEd254>()?;
2134        test_ultra_plonk_flag_helper::<FqEd377>()?;
2135        test_ultra_plonk_flag_helper::<FqEd381>()?;
2136        test_ultra_plonk_flag_helper::<Fq377>()
2137    }
2138
2139    fn test_ultra_plonk_flag_helper<F: PrimeField>() -> Result<(), CircuitError> {
2140        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
2141        // Check that below methods return errors when not in UltraPlonk mode.
2142        assert!(circuit.add_range_check_variable(0).is_err());
2143        circuit.finalize_for_arithmetization()?;
2144        assert!(circuit.compute_range_table_polynomial().is_err());
2145        assert!(circuit.compute_key_table_polynomial().is_err());
2146        assert!(circuit.compute_merged_lookup_table(F::one()).is_err());
2147        assert!(circuit
2148            .compute_lookup_sorted_vec_polynomials(F::one(), &[])
2149            .is_err());
2150        assert!(circuit
2151            .compute_lookup_prod_polynomial(&F::one(), &F::one(), &F::one(), &[], &[])
2152            .is_err());
2153
2154        Ok(())
2155    }
2156
2157    #[test]
2158    fn test_finalized_flag() -> Result<(), CircuitError> {
2159        test_finalized_flag_helper::<FqEd254>()?;
2160        test_finalized_flag_helper::<FqEd377>()?;
2161        test_finalized_flag_helper::<FqEd381>()?;
2162        test_finalized_flag_helper::<Fq377>()
2163    }
2164
2165    fn test_finalized_flag_helper<F: PrimeField>() -> Result<(), CircuitError> {
2166        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_turbo_plonk();
2167        // Should not call arithmetization methods before finalizing the circuit.
2168        assert!(circuit.compute_selector_polynomials().is_err());
2169        assert!(circuit.compute_extended_permutation_polynomials().is_err());
2170        assert!(circuit.compute_pub_input_polynomial().is_err());
2171        assert!(circuit.compute_wire_polynomials().is_err());
2172        assert!(circuit
2173            .compute_prod_permutation_polynomial(&F::one(), &F::one())
2174            .is_err());
2175
2176        // Should not insert gates or add variables after finalizing the circuit.
2177        circuit.finalize_for_arithmetization()?;
2178        assert!(circuit.create_variable(F::one()).is_err());
2179        assert!(circuit.create_public_variable(F::one()).is_err());
2180        assert!(circuit.add_gate(0, 0, 0).is_err());
2181        assert!(circuit.sub_gate(0, 0, 0).is_err());
2182        assert!(circuit.mul_gate(0, 0, 0).is_err());
2183        assert!(circuit.enforce_constant(0, F::one()).is_err());
2184        assert!(circuit.enforce_bool(0).is_err());
2185        assert!(circuit.enforce_equal(0, 0).is_err());
2186
2187        Ok(())
2188    }
2189
2190    #[test]
2191
2192    fn test_ultra_plonk_finalized_flag() -> Result<(), CircuitError> {
2193        test_ultra_plonk_finalized_flag_helper::<FqEd254>()?;
2194        test_ultra_plonk_finalized_flag_helper::<FqEd377>()?;
2195        test_ultra_plonk_finalized_flag_helper::<FqEd381>()?;
2196        test_ultra_plonk_finalized_flag_helper::<Fq377>()
2197    }
2198
2199    fn test_ultra_plonk_finalized_flag_helper<F: PrimeField>() -> Result<(), CircuitError> {
2200        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_ultra_plonk(1);
2201        // Should not call arithmetization methods before finalizing the circuit.
2202        assert!(circuit.compute_selector_polynomials().is_err());
2203        assert!(circuit.compute_extended_permutation_polynomials().is_err());
2204        assert!(circuit.compute_pub_input_polynomial().is_err());
2205        assert!(circuit.compute_wire_polynomials().is_err());
2206        assert!(circuit
2207            .compute_prod_permutation_polynomial(&F::one(), &F::one())
2208            .is_err());
2209        assert!(circuit.compute_range_table_polynomial().is_err());
2210        assert!(circuit.compute_key_table_polynomial().is_err());
2211        assert!(circuit.compute_merged_lookup_table(F::one()).is_err());
2212        assert!(circuit
2213            .compute_lookup_sorted_vec_polynomials(F::one(), &[])
2214            .is_err());
2215        assert!(circuit
2216            .compute_lookup_prod_polynomial(&F::one(), &F::one(), &F::one(), &[], &[])
2217            .is_err());
2218
2219        // Should not insert gates or add variables after finalizing the circuit.
2220        circuit.finalize_for_arithmetization()?;
2221        assert!(circuit.create_variable(F::one()).is_err());
2222        assert!(circuit.create_public_variable(F::one()).is_err());
2223        assert!(circuit.add_gate(0, 0, 0).is_err());
2224        assert!(circuit.sub_gate(0, 0, 0).is_err());
2225        assert!(circuit.mul_gate(0, 0, 0).is_err());
2226        assert!(circuit.enforce_constant(0, F::one()).is_err());
2227        assert!(circuit.enforce_bool(0).is_err());
2228        assert!(circuit.enforce_equal(0, 0).is_err());
2229        // Plookup-related methods
2230        assert!(circuit.add_range_check_variable(0).is_err());
2231
2232        Ok(())
2233    }
2234
2235    // Test arithmetizations
2236    //
2237    #[test]
2238    fn test_arithmetization() -> Result<(), CircuitError> {
2239        test_arithmetization_helper::<FqEd254>()?;
2240        test_arithmetization_helper::<FqEd377>()?;
2241        test_arithmetization_helper::<FqEd381>()?;
2242        test_arithmetization_helper::<Fq377>()
2243    }
2244
2245    fn test_arithmetization_helper<F: PrimeField>() -> Result<(), CircuitError> {
2246        // Create the TurboPlonk circuit
2247        let (mut circuit, pub_inputs) = create_turbo_plonk_instance::<F>()?;
2248        circuit.finalize_for_arithmetization()?;
2249        test_arithmetization_for_circuit(circuit, pub_inputs)?;
2250
2251        // Create the UltraPlonk circuit
2252        let (mut circuit, pub_inputs) = create_ultra_plonk_instance::<F>()?;
2253        circuit.finalize_for_arithmetization()?;
2254        test_arithmetization_for_lookup_circuit(&circuit)?;
2255        test_arithmetization_for_circuit(circuit, pub_inputs)?;
2256
2257        Ok(())
2258    }
2259
2260    // Check that the polynomial `poly` is consistent with the evaluations `evals`
2261    // over the domain.
2262    fn check_polynomial<F: PrimeField>(poly: &DensePolynomial<F>, evals: &[F]) {
2263        let domain = Radix2EvaluationDomain::new(evals.len()).unwrap();
2264        let poly_eval = poly.evaluate_over_domain_by_ref(domain);
2265        for (&a, &b) in poly_eval.evals.iter().zip(evals.iter()) {
2266            assert_eq!(a, b);
2267        }
2268    }
2269
2270    pub(crate) fn test_arithmetization_for_lookup_circuit<F: PrimeField>(
2271        circuit: &PlonkCircuit<F>,
2272    ) -> Result<(), CircuitError> {
2273        let n = circuit.eval_domain.size();
2274
2275        // Check range table polynomial
2276        let range_table_poly = circuit.compute_range_table_polynomial()?;
2277        let range_table = circuit.compute_range_table()?;
2278        check_polynomial(&range_table_poly, &range_table);
2279
2280        // Check key table polynomial
2281        let key_table_poly = circuit.compute_key_table_polynomial()?;
2282        let key_table = circuit.table_key_vec();
2283        check_polynomial(&key_table_poly, &key_table);
2284
2285        // Check sorted vector polynomials
2286        let rng = &mut test_rng();
2287        let tau = F::rand(rng);
2288        let merged_lookup_table = circuit.compute_merged_lookup_table(tau)?;
2289        let (sorted_vec, h1_poly, h2_poly) =
2290            circuit.compute_lookup_sorted_vec_polynomials(tau, &merged_lookup_table)?;
2291        assert_eq!(sorted_vec.len(), 2 * n - 1);
2292        // check that sorted_vec is sorted according to the order of
2293        // `merged_lookup_table`.
2294        assert_eq!(sorted_vec[0], merged_lookup_table[0]);
2295        let mut ptr = 1;
2296        for slice in sorted_vec.windows(2) {
2297            // find the next different value in `sorted_vec`
2298            if slice[0] == slice[1] {
2299                continue;
2300            }
2301            // find the next different value in `merged_lookup_table`
2302            while ptr < n && merged_lookup_table[ptr] == merged_lookup_table[ptr - 1] {
2303                ptr += 1;
2304            }
2305            assert!(ptr < n);
2306            assert_eq!(merged_lookup_table[ptr], slice[1]);
2307            ptr += 1;
2308        }
2309        // assert that the elements in `merged_lookup_table` have been exhausted
2310        assert_eq!(ptr, n);
2311
2312        check_polynomial(&h1_poly, &sorted_vec[..n]);
2313        check_polynomial(&h2_poly, &sorted_vec[n - 1..]);
2314
2315        // Check product accumulation polynomial
2316        let beta = F::rand(rng);
2317        let gamma = F::rand(rng);
2318        let prod_poly = circuit.compute_lookup_prod_polynomial(
2319            &tau,
2320            &beta,
2321            &gamma,
2322            &merged_lookup_table,
2323            &sorted_vec,
2324        )?;
2325        let mut prod_evals = vec![F::one()];
2326        let one_plus_beta = F::one() + beta;
2327        let gamma_mul_one_plus_beta = gamma * one_plus_beta;
2328        let q_lookup_vec = circuit.q_lookup();
2329        let q_dom_sep = circuit.q_dom_sep();
2330        for j in 0..(n - 2) {
2331            let lookup_wire_val =
2332                circuit.merged_lookup_wire_value(tau, j, &q_lookup_vec, &q_dom_sep)?;
2333            let table_val = merged_lookup_table[j];
2334            let table_next_val = merged_lookup_table[j + 1];
2335            let h1_val = sorted_vec[j];
2336            let h1_next_val = sorted_vec[j + 1];
2337            let h2_val = sorted_vec[n - 1 + j];
2338            let h2_next_val = sorted_vec[n + j];
2339
2340            // Nominator
2341            let a = one_plus_beta
2342                * (gamma + lookup_wire_val)
2343                * (gamma_mul_one_plus_beta + table_val + beta * table_next_val);
2344            // Denominator
2345            let b = (gamma_mul_one_plus_beta + h1_val + beta * h1_next_val)
2346                * (gamma_mul_one_plus_beta + h2_val + beta * h2_next_val);
2347            let prod = prod_evals[j] * a / b;
2348            prod_evals.push(prod);
2349        }
2350        prod_evals.push(F::one());
2351        check_polynomial(&prod_poly, &prod_evals);
2352
2353        Ok(())
2354    }
2355
2356    pub(crate) fn test_arithmetization_for_circuit<F: PrimeField>(
2357        circuit: PlonkCircuit<F>,
2358        pub_inputs: Vec<F>,
2359    ) -> Result<(), CircuitError> {
2360        // Check arithmetizations
2361        let n = circuit.eval_domain.size();
2362
2363        // Check selector polynomials
2364        let selector_polys = circuit.compute_selector_polynomials()?;
2365        selector_polys
2366            .iter()
2367            .zip(circuit.all_selectors().iter())
2368            .for_each(|(poly, evals)| check_polynomial(poly, evals));
2369
2370        // Check wire witness polynomials
2371        let wire_polys = circuit.compute_wire_polynomials()?;
2372        for (poly, wire_vars) in wire_polys
2373            .iter()
2374            .zip(circuit.wire_variables.iter().take(circuit.num_wire_types()))
2375        {
2376            let wire_evals: Vec<F> = wire_vars.iter().map(|&var| circuit.witness[var]).collect();
2377            check_polynomial(poly, &wire_evals);
2378        }
2379
2380        // Check public input polynomial
2381        let pi_poly = circuit.compute_pub_input_polynomial()?;
2382        let mut pi_evals = pub_inputs;
2383        pi_evals.extend(vec![F::zero(); n - 2]);
2384        check_polynomial(&pi_poly, &pi_evals);
2385
2386        // Check extended permutation polynomials
2387        let sigma_polys = circuit.compute_extended_permutation_polynomials()?;
2388        let extended_perm: Vec<F> = circuit
2389            .wire_permutation
2390            .iter()
2391            .map(|&(i, j)| circuit.extended_id_permutation[i * n + j])
2392            .collect();
2393        for (i, poly) in sigma_polys.iter().enumerate() {
2394            check_polynomial(poly, &extended_perm[i * n..(i + 1) * n]);
2395        }
2396
2397        // Check grand product polynomial for permutation
2398        let rng = &mut test_rng();
2399        let beta = F::rand(rng);
2400        let gamma = F::rand(rng);
2401        let prod_poly = circuit.compute_prod_permutation_polynomial(&beta, &gamma)?;
2402        let mut prod_evals = vec![F::one()];
2403        for j in 0..(n - 1) {
2404            // Nominator
2405            let mut a = F::one();
2406            // Denominator
2407            let mut b = F::one();
2408            for i in 0..circuit.num_wire_types {
2409                let wire_value = circuit.witness[circuit.wire_variable(i, j)];
2410                a *= wire_value + beta * circuit.extended_id_permutation[i * n + j] + gamma;
2411                b *= wire_value + beta * extended_perm[i * n + j] + gamma;
2412            }
2413            let prod = prod_evals[j] * a / b;
2414            prod_evals.push(prod);
2415        }
2416        check_polynomial(&prod_poly, &prod_evals);
2417
2418        Ok(())
2419    }
2420}