snarkvm_circuit_types_integers/
add_wrapped.rs1use super::*;
17
18impl<E: Environment, I: IntegerType> AddWrapped<Self> for Integer<E, I> {
19 type Output = Self;
20
21 #[inline]
22 fn add_wrapped(&self, other: &Integer<E, I>) -> Self::Output {
23 if self.is_constant() && other.is_constant() {
25 witness!(|self, other| console::Integer::new(self.wrapping_add(&other)))
27 } else {
28 let sum = self.to_field() + other.to_field();
32
33 let mut bits_le = sum.to_lower_bits_le(I::BITS as usize + 1);
35 bits_le.pop();
37
38 Integer { bits_le, phantom: Default::default() }
40 }
41 }
42}
43
44impl<E: Environment, I: IntegerType> Metrics<dyn AddWrapped<Integer<E, I>, Output = Integer<E, I>>> for Integer<E, I> {
45 type Case = (Mode, Mode);
46
47 fn count(case: &Self::Case) -> Count {
48 match (case.0, case.1) {
49 (Mode::Constant, Mode::Constant) => Count::is(I::BITS, 0, 0, 0),
50 (_, _) => Count::is(0, 0, I::BITS + 1, I::BITS + 2),
51 }
52 }
53}
54
55impl<E: Environment, I: IntegerType> OutputMode<dyn AddWrapped<Integer<E, I>, Output = Integer<E, I>>>
56 for Integer<E, I>
57{
58 type Case = (Mode, Mode);
59
60 fn output_mode(case: &Self::Case) -> Mode {
61 match (case.0, case.1) {
62 (Mode::Constant, Mode::Constant) => Mode::Constant,
63 (_, _) => Mode::Private,
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use snarkvm_circuit_environment::Circuit;
72
73 use core::ops::RangeInclusive;
74
75 const ITERATIONS: u64 = 128;
76
77 fn check_add<I: IntegerType>(
78 name: &str,
79 first: console::Integer<<Circuit as Environment>::Network, I>,
80 second: console::Integer<<Circuit as Environment>::Network, I>,
81 mode_a: Mode,
82 mode_b: Mode,
83 ) {
84 let a = Integer::<Circuit, I>::new(mode_a, first);
85 let b = Integer::new(mode_b, second);
86 let expected = first.wrapping_add(&second);
87 Circuit::scope(name, || {
88 let candidate = a.add_wrapped(&b);
89 assert_eq!(expected, *candidate.eject_value());
90 assert_eq!(console::Integer::new(expected), candidate.eject_value());
91 assert_count!(AddWrapped(Integer<I>, Integer<I>) => Integer<I>, &(mode_a, mode_b));
92 assert_output_mode!(AddWrapped(Integer<I>, Integer<I>) => Integer<I>, &(mode_a, mode_b), candidate);
93 });
94 Circuit::reset();
95 }
96
97 fn run_test<I: IntegerType>(mode_a: Mode, mode_b: Mode) {
98 let mut rng = TestRng::default();
99
100 for i in 0..ITERATIONS {
101 let first = Uniform::rand(&mut rng);
102 let second = Uniform::rand(&mut rng);
103
104 let name = format!("Add: {mode_a} + {mode_b} {i}");
105 check_add::<I>(&name, first, second, mode_a, mode_b);
106 check_add::<I>(&name, second, first, mode_a, mode_b); }
108
109 check_add::<I>("MAX + 1", console::Integer::MAX, console::Integer::one(), mode_a, mode_b);
111 check_add::<I>("1 + MAX", console::Integer::one(), console::Integer::MAX, mode_a, mode_b);
112
113 if I::is_signed() {
115 check_add::<I>("MIN + (-1)", console::Integer::MIN, -console::Integer::one(), mode_a, mode_b);
116 check_add::<I>("-1 + MIN", -console::Integer::one(), console::Integer::MIN, mode_a, mode_b);
117 }
118 }
119
120 fn run_exhaustive_test<I: IntegerType>(mode_a: Mode, mode_b: Mode)
121 where
122 RangeInclusive<I>: Iterator<Item = I>,
123 {
124 for first in I::MIN..=I::MAX {
125 for second in I::MIN..=I::MAX {
126 let first = console::Integer::<_, I>::new(first);
127 let second = console::Integer::<_, I>::new(second);
128
129 let name = format!("Add: ({first} + {second})");
130 check_add::<I>(&name, first, second, mode_a, mode_b);
131 }
132 }
133 }
134
135 test_integer_binary!(run_test, i8, plus);
136 test_integer_binary!(run_test, i16, plus);
137 test_integer_binary!(run_test, i32, plus);
138 test_integer_binary!(run_test, i64, plus);
139 test_integer_binary!(run_test, i128, plus);
140
141 test_integer_binary!(run_test, u8, plus);
142 test_integer_binary!(run_test, u16, plus);
143 test_integer_binary!(run_test, u32, plus);
144 test_integer_binary!(run_test, u64, plus);
145 test_integer_binary!(run_test, u128, plus);
146
147 test_integer_binary!(#[ignore], run_exhaustive_test, u8, plus, exhaustive);
148 test_integer_binary!(#[ignore], run_exhaustive_test, i8, plus, exhaustive);
149}