snarkvm_circuit_types_field/
add.rs1use 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 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}