Skip to main content

bellperson/util_cs/
mod.rs

1use crate::LinearCombination;
2use ff::PrimeField;
3
4pub mod bench_cs;
5pub mod metric_cs;
6pub use bellpepper_core::test_cs;
7pub mod witness_cs;
8
9pub type Constraint<Scalar> = (
10    LinearCombination<Scalar>,
11    LinearCombination<Scalar>,
12    LinearCombination<Scalar>,
13    String,
14);
15
16pub trait Comparable<Scalar: PrimeField> {
17    /// The `Comparable` trait allows comparison of two constraint systems which
18    /// implement the trait. The only non-trivial method, `delta`, has a default
19    /// implementation which supplies the desired behavior.
20    ///
21    /// Use `delta` to compare constraint systems. If they are not identical, the
22    /// returned `Delta` enum contains fine-grained information about how they
23    /// differ. This can be especially useful when debugging the situation in which
24    /// a constraint system is satisfied, but the corresponding Groth16 proof does
25    /// not verify.
26    ///
27    /// If `ignore_counts` is  true, count mismatches will be ignored, and any constraint
28    /// mismatch will be returned. This is useful in pinpointing the source of a mismatch.
29    ///
30    /// Example usage:
31    ///
32    /// ```norun
33    /// let delta = cs.delta(&cs_blank, false);
34    /// assert!(delta == Delta::Equal);
35    /// ```
36    fn num_inputs(&self) -> usize;
37    fn num_constraints(&self) -> usize;
38    fn inputs(&self) -> Vec<String>;
39    fn aux(&self) -> Vec<String>;
40    fn constraints(&self) -> &[Constraint<Scalar>];
41
42    fn delta<C: Comparable<Scalar>>(&self, other: &C, ignore_counts: bool) -> Delta<Scalar>
43    where
44        Scalar: PrimeField,
45    {
46        let input_count_matches = self.num_inputs() == other.num_inputs();
47        let constraint_count_matches = self.num_constraints() == other.num_constraints();
48
49        let inputs_match = self.inputs() == other.inputs();
50        let constraints_match = self.constraints() == other.constraints();
51
52        let equal =
53            input_count_matches && constraint_count_matches && inputs_match && constraints_match;
54
55        if !ignore_counts && !input_count_matches {
56            Delta::InputCountMismatch(self.num_inputs(), other.num_inputs())
57        } else if !ignore_counts && !constraint_count_matches {
58            Delta::ConstraintCountMismatch(self.num_constraints(), other.num_constraints())
59        } else if !constraints_match {
60            let c = self.constraints();
61            let o = other.constraints();
62
63            let mismatch = c
64                .iter()
65                .zip(o)
66                .enumerate()
67                .filter(|(_, (a, b))| a != b)
68                .map(|(i, (a, b))| (i, a, b))
69                .next();
70
71            let m = mismatch.unwrap();
72
73            Delta::ConstraintMismatch(m.0, m.1.clone(), m.2.clone())
74        } else if equal {
75            Delta::Equal
76        } else {
77            Delta::Different
78        }
79    }
80}
81
82#[allow(clippy::large_enum_variant)]
83#[derive(Clone, Debug, PartialEq)]
84pub enum Delta<Scalar: PrimeField> {
85    Equal,
86    Different,
87    InputCountMismatch(usize, usize),
88    ConstraintCountMismatch(usize, usize),
89    ConstraintMismatch(usize, Constraint<Scalar>, Constraint<Scalar>),
90}