fullcodec_plonk/constraint_system/
arithmetic.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use crate::constraint_system::{Constraint, TurboComposer, Witness};
8use dusk_bls12_381::BlsScalar;
9
10impl TurboComposer {
11    /// Evaluate and return `o` by appending a new constraint into the circuit.
12    ///
13    /// The output of the constraint will be overwritten with
14    /// `o := q_l · a + q_r · b + q_4 · d + q_c + PI`
15    pub fn gate_add(&mut self, s: Constraint) -> Witness {
16        let s = Constraint::arithmetic(&s).output(-BlsScalar::one());
17
18        let o = self.append_output_witness(s);
19        let s = s.o(o);
20
21        self.append_gate(s);
22
23        o
24    }
25
26    /// Evaluate and return `o` by appending a new constraint into the circuit.
27    ///
28    /// The output of the constraint will be overwritten with
29    /// `o := q_m · a · b + q_4 · d + q_c + PI`
30    pub fn gate_mul(&mut self, s: Constraint) -> Witness {
31        let s = Constraint::arithmetic(&s).output(-BlsScalar::one());
32
33        let o = self.append_output_witness(s);
34        let s = s.o(o);
35
36        self.append_gate(s);
37
38        o
39    }
40}
41
42#[cfg(feature = "std")]
43#[cfg(test)]
44mod tests {
45    use crate::constraint_system::{helper, Constraint};
46    use dusk_bls12_381::BlsScalar;
47
48    #[test]
49    fn test_public_inputs() {
50        helper::gadget_tester(
51            |composer| {
52                let one = composer.append_witness(BlsScalar::one());
53
54                composer.append_dummy_gates();
55
56                let constraint =
57                    Constraint::new().left(1).right(1).public(1).a(one).b(one);
58                let should_be_three = composer.gate_add(constraint);
59
60                composer.assert_equal_constant(
61                    should_be_three,
62                    BlsScalar::from(3),
63                    None,
64                );
65
66                let constraint =
67                    Constraint::new().left(1).right(1).public(2).a(one).b(one);
68                let should_be_four = composer.gate_add(constraint);
69
70                composer.assert_equal_constant(
71                    should_be_four,
72                    BlsScalar::from(4),
73                    None,
74                );
75            },
76            200,
77        )
78        .expect("Failed to test circuit public inputs");
79    }
80
81    #[test]
82    fn test_correct_add_mul_gate() {
83        let res = helper::gadget_tester(
84            |composer| {
85                // Verify that (4+5+5) * (6+7+7) = 280
86                let four = composer.append_witness(BlsScalar::from(4));
87                let five = composer.append_witness(BlsScalar::from(5));
88                let six = composer.append_witness(BlsScalar::from(6));
89                let seven = composer.append_witness(BlsScalar::from(7));
90
91                let constraint = Constraint::new()
92                    .left(1)
93                    .right(1)
94                    .fourth(1)
95                    .a(four)
96                    .b(five)
97                    .d(five);
98                let fourteen = composer.gate_add(constraint);
99
100                let constraint = Constraint::new()
101                    .left(1)
102                    .right(1)
103                    .fourth(1)
104                    .a(six)
105                    .b(seven)
106                    .d(seven);
107                let twenty = composer.gate_add(constraint);
108
109                // There are quite a few ways to check the equation is correct,
110                // depending on your circumstance If we already
111                // have the output wire, we can constrain the output of the
112                // mul_gate to be equal to it If we do not, we
113                // can compute it using the `mul` If the output
114                // is public, we can also constrain the output wire of the mul
115                // gate to it. This is what this test does
116                let constraint =
117                    Constraint::new().mult(1).a(fourteen).b(twenty);
118                let output = composer.gate_mul(constraint);
119
120                composer.assert_equal_constant(
121                    output,
122                    BlsScalar::from(280),
123                    None,
124                );
125            },
126            200,
127        );
128        assert!(res.is_ok());
129    }
130
131    #[test]
132    fn test_correct_add_gate() {
133        helper::gadget_tester(
134            |composer| {
135                let one = composer.append_witness(BlsScalar::one());
136
137                let constraint = Constraint::new().left(1).constant(2).a(one);
138                let c = composer.gate_add(constraint);
139
140                composer.assert_equal_constant(c, BlsScalar::from(3), None);
141            },
142            32,
143        )
144        .expect("Circuit consistency failed");
145    }
146
147    #[test]
148    fn test_correct_big_add_mul_gate() {
149        let res = helper::gadget_tester(
150            |composer| {
151                // Verify that (4+5+5) * (6+7+7) + (8*9) = 352
152                let four = composer.append_witness(BlsScalar::from(4));
153                let five = composer.append_witness(BlsScalar::from(5));
154                let six = composer.append_witness(BlsScalar::from(6));
155                let seven = composer.append_witness(BlsScalar::from(7));
156                let nine = composer.append_witness(BlsScalar::from(9));
157
158                let constraint = Constraint::new()
159                    .left(1)
160                    .right(1)
161                    .fourth(1)
162                    .a(four)
163                    .b(five)
164                    .d(five);
165                let fourteen = composer.gate_add(constraint);
166
167                let constraint = Constraint::new()
168                    .left(1)
169                    .right(1)
170                    .fourth(1)
171                    .a(six)
172                    .b(seven)
173                    .d(seven);
174                let twenty = composer.gate_add(constraint);
175
176                let constraint = Constraint::new()
177                    .mult(1)
178                    .fourth(8)
179                    .a(fourteen)
180                    .b(twenty)
181                    .d(nine);
182                let output = composer.gate_mul(constraint);
183
184                composer.assert_equal_constant(
185                    output,
186                    BlsScalar::from(352),
187                    None,
188                );
189            },
190            200,
191        );
192        assert!(res.is_ok());
193    }
194
195    #[test]
196    fn test_incorrect_add_mul_gate() {
197        let res = helper::gadget_tester(
198            |composer| {
199                // Verify that (5+5) * (6+7) != 117
200                let five = composer.append_witness(BlsScalar::from(5));
201                let six = composer.append_witness(BlsScalar::from(6));
202                let seven = composer.append_witness(BlsScalar::from(7));
203
204                let constraint =
205                    Constraint::new().left(1).right(1).a(five).b(five);
206                let five_plus_five = composer.gate_add(constraint);
207
208                let constraint =
209                    Constraint::new().left(1).right(1).a(six).b(seven);
210                let six_plus_seven = composer.gate_add(constraint);
211
212                let constraint = Constraint::new()
213                    .mult(1)
214                    .a(five_plus_five)
215                    .b(six_plus_seven);
216                let output = composer.gate_mul(constraint);
217
218                composer.assert_equal_constant(
219                    output,
220                    BlsScalar::from(117),
221                    None,
222                );
223            },
224            200,
225        );
226        assert!(res.is_err());
227    }
228}