snarkvm_circuit_types_field/
sub.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> Sub<Field<E>> for Field<E> {
19    type Output = Self;
20
21    fn sub(self, other: Field<E>) -> Self::Output {
22        self - &other
23    }
24}
25
26impl<E: Environment> Sub<&Field<E>> for Field<E> {
27    type Output = Self;
28
29    fn sub(self, other: &Field<E>) -> Self::Output {
30        let mut result = self;
31        result -= other;
32        result
33    }
34}
35
36impl<E: Environment> Sub<Field<E>> for &Field<E> {
37    type Output = Field<E>;
38
39    fn sub(self, other: Field<E>) -> Self::Output {
40        self - &other
41    }
42}
43
44impl<E: Environment> Sub<&Field<E>> for &Field<E> {
45    type Output = Field<E>;
46
47    fn sub(self, other: &Field<E>) -> Self::Output {
48        let mut result = self.clone();
49        result -= other;
50        result
51    }
52}
53
54impl<E: Environment> SubAssign<Field<E>> for Field<E> {
55    fn sub_assign(&mut self, other: Field<E>) {
56        *self -= &other;
57    }
58}
59
60impl<E: Environment> SubAssign<&Field<E>> for Field<E> {
61    fn sub_assign(&mut self, other: &Field<E>) {
62        *self += -other;
63    }
64}
65
66impl<E: Environment> Metrics<dyn Sub<Field<E>, Output = Field<E>>> for Field<E> {
67    type Case = (Mode, Mode);
68
69    fn count(_case: &Self::Case) -> Count {
70        Count::is(0, 0, 0, 0)
71    }
72}
73
74impl<E: Environment> OutputMode<dyn Sub<Field<E>, Output = Field<E>>> for Field<E> {
75    type Case = (CircuitType<Field<E>>, CircuitType<Field<E>>);
76
77    fn output_mode(case: &Self::Case) -> Mode {
78        match (case.0.mode(), case.1.mode()) {
79            (Mode::Constant, Mode::Constant) => Mode::Constant,
80            (Mode::Public, Mode::Constant) => match &case.1 {
81                CircuitType::Constant(constant) => match constant.eject_value().is_zero() {
82                    true => Mode::Public,
83                    false => Mode::Private,
84                },
85                _ => E::halt("The constant is required to determine the output mode of Public + Constant"),
86            },
87            (_, _) => Mode::Private,
88        }
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95    use snarkvm_circuit_environment::Circuit;
96
97    const ITERATIONS: u64 = 10_000;
98
99    fn check_sub(
100        name: &str,
101        expected: &console::Field<<Circuit as Environment>::Network>,
102        a: &Field<Circuit>,
103        b: &Field<Circuit>,
104    ) {
105        Circuit::scope(name, || {
106            let candidate = a - b;
107            assert_eq!(*expected, candidate.eject_value(), "({} - {})", a.eject_value(), b.eject_value());
108            assert_count!(Sub(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
109            assert_output_mode!(Sub(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
110        });
111    }
112
113    fn check_sub_assign(
114        name: &str,
115        expected: &console::Field<<Circuit as Environment>::Network>,
116        a: &Field<Circuit>,
117        b: &Field<Circuit>,
118    ) {
119        Circuit::scope(name, || {
120            let mut candidate = a.clone();
121            candidate -= b;
122            assert_eq!(*expected, candidate.eject_value(), "({} - {})", a.eject_value(), b.eject_value());
123            assert_count!(Sub(Field, Field) => Field, &(a.eject_mode(), b.eject_mode()));
124            assert_output_mode!(Sub(Field, Field) => Field, &(CircuitType::from(a), CircuitType::from(b)), candidate);
125        });
126    }
127
128    fn run_test(mode_a: Mode, mode_b: Mode) {
129        let mut rng = TestRng::default();
130
131        for i in 0..ITERATIONS {
132            let first = Uniform::rand(&mut rng);
133            let second = Uniform::rand(&mut rng);
134
135            let expected = first - second;
136            let a = Field::<Circuit>::new(mode_a, first);
137            let b = Field::<Circuit>::new(mode_b, second);
138
139            let name = format!("Sub: a - b {i}");
140            check_sub(&name, &expected, &a, &b);
141            let name = format!("SubAssign: a - b {i}");
142            check_sub_assign(&name, &expected, &a, &b);
143
144            // Test identity.
145            let name = format!("Sub: a - 0 {i}");
146            let zero = Field::<Circuit>::new(mode_b, console::Field::<<Circuit as Environment>::Network>::zero());
147            check_sub(&name, &first, &a, &zero);
148            let name = format!("SubAssign: a - 0 {i}");
149            check_sub_assign(&name, &first, &a, &zero);
150
151            // Test negation.
152            let name = format!("Sub: 0 - b {i}");
153            let zero = Field::<Circuit>::new(mode_a, console::Field::<<Circuit as Environment>::Network>::zero());
154            check_sub(&name, &(-second), &zero, &b);
155            let name = format!("SubAssign: 0 - b {i}");
156            check_sub_assign(&name, &(-second), &zero, &b);
157        }
158    }
159
160    #[test]
161    fn test_constant_plus_constant() {
162        run_test(Mode::Constant, Mode::Constant);
163    }
164
165    #[test]
166    fn test_constant_plus_public() {
167        run_test(Mode::Constant, Mode::Public);
168    }
169
170    #[test]
171    fn test_public_plus_constant() {
172        run_test(Mode::Public, Mode::Constant);
173    }
174
175    #[test]
176    fn test_constant_plus_private() {
177        run_test(Mode::Constant, Mode::Private);
178    }
179
180    #[test]
181    fn test_private_plus_constant() {
182        run_test(Mode::Private, Mode::Constant);
183    }
184
185    #[test]
186    fn test_public_plus_public() {
187        run_test(Mode::Public, Mode::Public);
188    }
189
190    #[test]
191    fn test_public_plus_private() {
192        run_test(Mode::Public, Mode::Private);
193    }
194
195    #[test]
196    fn test_private_plus_public() {
197        run_test(Mode::Private, Mode::Public);
198    }
199
200    #[test]
201    fn test_private_plus_private() {
202        run_test(Mode::Private, Mode::Private);
203    }
204
205    #[test]
206    fn test_0_minus_0() {
207        let zero = console::Field::<<Circuit as Environment>::Network>::zero();
208
209        let candidate = Field::<Circuit>::zero() - Field::zero();
210        assert_eq!(zero, candidate.eject_value());
211
212        let candidate = Field::<Circuit>::zero() - &Field::zero();
213        assert_eq!(zero, candidate.eject_value());
214
215        let candidate = Field::<Circuit>::new(Mode::Public, zero) - Field::new(Mode::Public, zero);
216        assert_eq!(zero, candidate.eject_value());
217
218        let candidate = Field::<Circuit>::new(Mode::Public, zero) - Field::new(Mode::Private, zero);
219        assert_eq!(zero, candidate.eject_value());
220
221        let candidate = Field::<Circuit>::new(Mode::Private, zero) - Field::new(Mode::Private, zero);
222        assert_eq!(zero, candidate.eject_value());
223    }
224
225    #[test]
226    fn test_1_minus_0() {
227        let zero = console::Field::<<Circuit as Environment>::Network>::zero();
228        let one = console::Field::<<Circuit as Environment>::Network>::one();
229
230        let candidate = Field::<Circuit>::one() - Field::zero();
231        assert_eq!(one, candidate.eject_value());
232
233        let candidate = Field::<Circuit>::one() - &Field::zero();
234        assert_eq!(one, candidate.eject_value());
235
236        let candidate = Field::<Circuit>::new(Mode::Public, one) - Field::new(Mode::Public, zero);
237        assert_eq!(one, candidate.eject_value());
238
239        let candidate = Field::<Circuit>::new(Mode::Public, one) - Field::new(Mode::Private, zero);
240        assert_eq!(one, candidate.eject_value());
241
242        let candidate = Field::<Circuit>::new(Mode::Private, one) - Field::new(Mode::Private, zero);
243        assert_eq!(one, candidate.eject_value());
244    }
245
246    #[test]
247    fn test_1_minus_1() {
248        let zero = console::Field::<<Circuit as Environment>::Network>::zero();
249        let one = console::Field::<<Circuit as Environment>::Network>::one();
250
251        let candidate = Field::<Circuit>::one() - Field::one();
252        assert_eq!(zero, candidate.eject_value());
253
254        let candidate = Field::<Circuit>::one() - &Field::one();
255        assert_eq!(zero, candidate.eject_value());
256
257        let candidate = Field::<Circuit>::new(Mode::Public, one) - Field::new(Mode::Public, one);
258        assert_eq!(zero, candidate.eject_value());
259
260        let candidate = Field::<Circuit>::new(Mode::Private, one) - Field::new(Mode::Public, one);
261        assert_eq!(zero, candidate.eject_value());
262
263        let candidate = Field::<Circuit>::new(Mode::Private, one) - Field::new(Mode::Private, one);
264        assert_eq!(zero, candidate.eject_value());
265    }
266
267    #[test]
268    fn test_2_minus_1() {
269        let one = console::Field::<<Circuit as Environment>::Network>::one();
270        let two = one + one;
271
272        let candidate_two = Field::<Circuit>::one() + Field::one();
273        let candidate = candidate_two - Field::one();
274        assert_eq!(one, candidate.eject_value());
275
276        let candidate_two = Field::<Circuit>::one() + &Field::one();
277        let candidate = candidate_two - &Field::one();
278        assert_eq!(one, candidate.eject_value());
279
280        let candidate = Field::<Circuit>::new(Mode::Public, two) - Field::new(Mode::Public, one);
281        assert_eq!(one, candidate.eject_value());
282
283        let candidate = Field::<Circuit>::new(Mode::Private, two) - Field::new(Mode::Public, one);
284        assert_eq!(one, candidate.eject_value());
285
286        let candidate = Field::<Circuit>::new(Mode::Private, two) - Field::new(Mode::Private, one);
287        assert_eq!(one, candidate.eject_value());
288    }
289}