snarkvm_circuit_types_field/
add.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<E: Environment> Add<Field<E>> for Field<E> {
19    type Output = Field<E>;
20
21    fn add(self, other: Field<E>) -> Self::Output {
22        self + &other
23    }
24}
25
26impl<E: Environment> Add<&Field<E>> for Field<E> {
27    type Output = Field<E>;
28
29    fn add(self, other: &Field<E>) -> Self::Output {
30        let mut result = self;
31        result += other;
32        result
33    }
34}
35
36impl<E: Environment> Add<Field<E>> for &Field<E> {
37    type Output = Field<E>;
38
39    fn add(self, other: Field<E>) -> Self::Output {
40        self + &other
41    }
42}
43
44impl<E: Environment> Add<&Field<E>> for &Field<E> {
45    type Output = Field<E>;
46
47    fn add(self, other: &Field<E>) -> Self::Output {
48        let mut result = self.clone();
49        result += other;
50        result
51    }
52}
53
54impl<E: Environment> AddAssign<Field<E>> for Field<E> {
55    fn add_assign(&mut self, other: Field<E>) {
56        *self += &other;
57    }
58}
59
60impl<E: Environment> AddAssign<&Field<E>> for Field<E> {
61    fn add_assign(&mut self, other: &Field<E>) {
62        self.linear_combination += &other.linear_combination;
63        self.bits_le = Default::default();
64    }
65}
66
67impl<E: Environment> Metrics<dyn Add<Field<E>, Output = Field<E>>> for Field<E> {
68    type Case = (Mode, Mode);
69
70    fn count(_case: &Self::Case) -> Count {
71        Count::is(0, 0, 0, 0)
72    }
73}
74
75impl<E: Environment> OutputMode<dyn Add<Field<E>, Output = Field<E>>> for Field<E> {
76    type Case = (CircuitType<Field<E>>, CircuitType<Field<E>>);
77
78    fn output_mode(case: &Self::Case) -> Mode {
79        match (case.0.mode(), case.1.mode()) {
80            (Mode::Constant, Mode::Constant) => Mode::Constant,
81            (Mode::Constant, Mode::Public) => match &case.0 {
82                CircuitType::Constant(constant) => match constant.eject_value().is_zero() {
83                    true => Mode::Public,
84                    false => Mode::Private,
85                },
86                _ => E::halt("The constant is required to determine the output mode of Public + Constant"),
87            },
88            (Mode::Public, Mode::Constant) => match &case.1 {
89                CircuitType::Constant(constant) => match constant.eject_value().is_zero() {
90                    true => Mode::Public,
91                    false => Mode::Private,
92                },
93                _ => E::halt("The constant is required to determine the output mode of Public + Constant"),
94            },
95            (_, _) => Mode::Private,
96        }
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use snarkvm_circuit_environment::Circuit;
104
105    const ITERATIONS: u64 = 10_000;
106
107    fn check_add(
108        name: &str,
109        expected: &console::Field<<Circuit as Environment>::Network>,
110        a: &Field<Circuit>,
111        b: &Field<Circuit>,
112    ) {
113        Circuit::scope(name, || {
114            let candidate = a + b;
115            assert_eq!(*expected, candidate.eject_value(), "({} + {})", a.eject_value(), b.eject_value());
116            assert_count!(Add(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
117            assert_output_mode!(Add(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
118        });
119    }
120
121    fn check_add_assign(
122        name: &str,
123        expected: &console::Field<<Circuit as Environment>::Network>,
124        a: &Field<Circuit>,
125        b: &Field<Circuit>,
126    ) {
127        Circuit::scope(name, || {
128            let mut candidate = a.clone();
129            candidate += b;
130            assert_eq!(*expected, candidate.eject_value(), "({} + {})", a.eject_value(), b.eject_value());
131            assert_count!(Add(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
132            assert_output_mode!(Add(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
133        });
134    }
135
136    fn run_test(mode_a: Mode, mode_b: Mode) {
137        let mut rng = TestRng::default();
138
139        for i in 0..ITERATIONS {
140            let first = Uniform::rand(&mut rng);
141            let second = Uniform::rand(&mut rng);
142
143            let expected = first + second;
144            let a = Field::<Circuit>::new(mode_a, first);
145            let b = Field::<Circuit>::new(mode_b, second);
146
147            let name = format!("Add: a + b {i}");
148            check_add(&name, &expected, &a, &b);
149            let name = format!("AddAssign: a + b {i}");
150            check_add_assign(&name, &expected, &a, &b);
151
152            // Test identity.
153            let name = format!("Add: a + 0 {i}");
154            let zero = Field::<Circuit>::new(mode_b, console::Field::<<Circuit as Environment>::Network>::zero());
155            check_add(&name, &first, &a, &zero);
156            let name = format!("AddAssign: a + 0 {i}");
157            check_add_assign(&name, &first, &a, &zero);
158
159            let name = format!("Add: 0 + b {i}");
160            let zero = Field::<Circuit>::new(mode_a, console::Field::<<Circuit as Environment>::Network>::zero());
161            check_add(&name, &second, &zero, &b);
162            let name = format!("AddAssign: 0 + b {i}");
163            check_add_assign(&name, &second, &zero, &b);
164        }
165    }
166
167    #[test]
168    fn test_constant_plus_constant() {
169        run_test(Mode::Constant, Mode::Constant);
170    }
171
172    #[test]
173    fn test_constant_plus_public() {
174        run_test(Mode::Constant, Mode::Public);
175    }
176
177    #[test]
178    fn test_public_plus_constant() {
179        run_test(Mode::Public, Mode::Constant);
180    }
181
182    #[test]
183    fn test_constant_plus_private() {
184        run_test(Mode::Constant, Mode::Private);
185    }
186
187    #[test]
188    fn test_private_plus_constant() {
189        run_test(Mode::Private, Mode::Constant);
190    }
191
192    #[test]
193    fn test_public_plus_public() {
194        run_test(Mode::Public, Mode::Public);
195    }
196
197    #[test]
198    fn test_public_plus_private() {
199        run_test(Mode::Public, Mode::Private);
200    }
201
202    #[test]
203    fn test_private_plus_public() {
204        run_test(Mode::Private, Mode::Public);
205    }
206
207    #[test]
208    fn test_private_plus_private() {
209        run_test(Mode::Private, Mode::Private);
210    }
211
212    #[test]
213    fn test_0_plus_0() {
214        let zero = console::Field::<<Circuit as Environment>::Network>::zero();
215
216        let candidate = Field::<Circuit>::zero() + Field::zero();
217        assert_eq!(zero, candidate.eject_value());
218
219        let candidate = Field::<Circuit>::zero() + &Field::zero();
220        assert_eq!(zero, candidate.eject_value());
221
222        let candidate = Field::<Circuit>::new(Mode::Public, zero) + Field::new(Mode::Public, zero);
223        assert_eq!(zero, candidate.eject_value());
224
225        let candidate = Field::<Circuit>::new(Mode::Public, zero) + Field::new(Mode::Private, zero);
226        assert_eq!(zero, candidate.eject_value());
227
228        let candidate = Field::<Circuit>::new(Mode::Private, zero) + Field::new(Mode::Private, zero);
229        assert_eq!(zero, candidate.eject_value());
230    }
231
232    #[test]
233    fn test_0_plus_1() {
234        let zero = console::Field::<<Circuit as Environment>::Network>::zero();
235        let one = console::Field::<<Circuit as Environment>::Network>::one();
236
237        let candidate = Field::<Circuit>::zero() + Field::one();
238        assert_eq!(one, candidate.eject_value());
239
240        let candidate = Field::<Circuit>::zero() + &Field::one();
241        assert_eq!(one, candidate.eject_value());
242
243        let candidate = Field::<Circuit>::one() + Field::zero();
244        assert_eq!(one, candidate.eject_value());
245
246        let candidate = Field::<Circuit>::one() + &Field::zero();
247        assert_eq!(one, candidate.eject_value());
248
249        let candidate = Field::<Circuit>::new(Mode::Public, one) + Field::new(Mode::Public, zero);
250        assert_eq!(one, candidate.eject_value());
251
252        let candidate = Field::<Circuit>::new(Mode::Public, one) + Field::new(Mode::Private, zero);
253        assert_eq!(one, candidate.eject_value());
254
255        let candidate = Field::<Circuit>::new(Mode::Private, one) + Field::new(Mode::Private, zero);
256        assert_eq!(one, candidate.eject_value());
257    }
258
259    #[test]
260    fn test_1_plus_1() {
261        let one = console::Field::<<Circuit as Environment>::Network>::one();
262        let two = one + one;
263
264        let candidate = Field::<Circuit>::one() + Field::one();
265        assert_eq!(two, candidate.eject_value());
266
267        let candidate = Field::<Circuit>::one() + &Field::one();
268        assert_eq!(two, candidate.eject_value());
269
270        let candidate = Field::<Circuit>::new(Mode::Public, one) + Field::new(Mode::Public, one);
271        assert_eq!(two, candidate.eject_value());
272
273        let candidate = Field::<Circuit>::new(Mode::Private, one) + Field::new(Mode::Public, one);
274        assert_eq!(two, candidate.eject_value());
275
276        let candidate = Field::<Circuit>::new(Mode::Private, one) + Field::new(Mode::Private, one);
277        assert_eq!(two, candidate.eject_value());
278    }
279
280    #[test]
281    fn test_1_plus_2() {
282        let one = console::Field::<<Circuit as Environment>::Network>::one();
283        let two = one + one;
284        let three = two + one;
285
286        let candidate_two = Field::<Circuit>::one() + Field::one();
287        let candidate = candidate_two + Field::one();
288        assert_eq!(three, candidate.eject_value());
289
290        let candidate_two = Field::<Circuit>::one() + &Field::one();
291        let candidate = candidate_two + &Field::one();
292        assert_eq!(three, candidate.eject_value());
293
294        let candidate = Field::<Circuit>::new(Mode::Public, one) + Field::new(Mode::Public, two);
295        assert_eq!(three, candidate.eject_value());
296
297        let candidate = Field::<Circuit>::new(Mode::Private, one) + Field::new(Mode::Public, two);
298        assert_eq!(three, candidate.eject_value());
299
300        let candidate = Field::<Circuit>::new(Mode::Private, one) + Field::new(Mode::Private, two);
301        assert_eq!(three, candidate.eject_value());
302    }
303}