bellpepper_core/util_cs/
mod.rs

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