crypto_bigint/int/
add.rs

1//! [`Int`] addition operations.
2
3use core::ops::{Add, AddAssign};
4
5use num_traits::WrappingAdd;
6use subtle::CtOption;
7
8use crate::{Checked, CheckedAdd, ConstChoice, ConstCtOption, Int, Wrapping};
9
10impl<const LIMBS: usize> Int<LIMBS> {
11    /// Perform checked addition. Returns `none` when the addition overflowed.
12    pub const fn checked_add(&self, rhs: &Self) -> ConstCtOption<Self> {
13        let (value, overflow) = self.overflowing_add(rhs);
14        ConstCtOption::new(value, overflow.not())
15    }
16
17    /// Perform addition, raising the `overflow` flag on overflow.
18    pub const fn overflowing_add(&self, rhs: &Self) -> (Self, ConstChoice) {
19        // Step 1. add operands
20        let res = Self(self.0.wrapping_add(&rhs.0));
21
22        // Step 2. determine whether overflow happened.
23        // Note:
24        // - overflow can only happen when the inputs have the same sign, and then
25        // - overflow occurs if and only if the result has the opposite sign of both inputs.
26        //
27        // We can thus express the overflow flag as: (self.msb == rhs.msb) & (self.msb != res.msb)
28        let self_msb = self.is_negative();
29        let overflow = self_msb
30            .eq(rhs.is_negative())
31            .and(self_msb.ne(res.is_negative()));
32
33        // Step 3. Construct result
34        (res, overflow)
35    }
36
37    /// Perform wrapping addition, discarding overflow.
38    pub const fn wrapping_add(&self, rhs: &Self) -> Self {
39        Self(self.0.wrapping_add(&rhs.0))
40    }
41}
42
43impl<const LIMBS: usize> Add for Int<LIMBS> {
44    type Output = Self;
45
46    fn add(self, rhs: Self) -> Self {
47        self.add(&rhs)
48    }
49}
50
51impl<const LIMBS: usize> Add<&Int<LIMBS>> for Int<LIMBS> {
52    type Output = Self;
53
54    fn add(self, rhs: &Self) -> Self {
55        CtOption::from(self.checked_add(rhs)).expect("attempted to add with overflow")
56    }
57}
58
59impl<const LIMBS: usize> AddAssign for Int<LIMBS> {
60    fn add_assign(&mut self, other: Self) {
61        *self += &other;
62    }
63}
64
65impl<const LIMBS: usize> AddAssign<&Int<LIMBS>> for Int<LIMBS> {
66    fn add_assign(&mut self, other: &Self) {
67        *self = *self + other;
68    }
69}
70
71impl<const LIMBS: usize> AddAssign for Wrapping<Int<LIMBS>> {
72    fn add_assign(&mut self, other: Self) {
73        *self = *self + other;
74    }
75}
76
77impl<const LIMBS: usize> AddAssign<&Wrapping<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
78    fn add_assign(&mut self, other: &Self) {
79        *self = *self + other;
80    }
81}
82
83impl<const LIMBS: usize> AddAssign for Checked<Int<LIMBS>> {
84    fn add_assign(&mut self, other: Self) {
85        *self = *self + other;
86    }
87}
88
89impl<const LIMBS: usize> AddAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
90    fn add_assign(&mut self, other: &Self) {
91        *self = *self + other;
92    }
93}
94
95impl<const LIMBS: usize> CheckedAdd for Int<LIMBS> {
96    fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
97        self.checked_add(rhs).into()
98    }
99}
100
101impl<const LIMBS: usize> WrappingAdd for Int<LIMBS> {
102    fn wrapping_add(&self, v: &Self) -> Self {
103        self.wrapping_add(v)
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::{ConstChoice, I128, U128};
110
111    #[test]
112    fn checked_add() {
113        let min_plus_one = I128 {
114            0: I128::MIN.0.wrapping_add(&I128::ONE.0),
115        };
116        let max_minus_one = I128 {
117            0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
118        };
119        let two = I128 {
120            0: U128::from(2u32),
121        };
122
123        // lhs = MIN
124
125        let result = I128::MIN.checked_add(&I128::MIN);
126        assert!(bool::from(result.is_none()));
127
128        let result = I128::MIN.checked_add(&I128::MINUS_ONE);
129        assert!(bool::from(result.is_none()));
130
131        let result = I128::MIN.checked_add(&I128::ZERO);
132        assert_eq!(result.unwrap(), I128::MIN);
133
134        let result = I128::MIN.checked_add(&I128::ONE);
135        assert_eq!(result.unwrap(), min_plus_one);
136
137        let result = I128::MIN.checked_add(&I128::MAX);
138        assert_eq!(result.unwrap(), I128::MINUS_ONE);
139
140        // lhs = -1
141
142        let result = I128::MINUS_ONE.checked_add(&I128::MIN);
143        assert!(bool::from(result.is_none()));
144
145        let result = I128::MINUS_ONE.checked_add(&I128::MINUS_ONE);
146        assert_eq!(result.unwrap(), two.checked_neg().unwrap());
147
148        let result = I128::MINUS_ONE.checked_add(&I128::ZERO);
149        assert_eq!(result.unwrap(), I128::MINUS_ONE);
150
151        let result = I128::MINUS_ONE.checked_add(&I128::ONE);
152        assert_eq!(result.unwrap(), I128::ZERO);
153
154        let result = I128::MINUS_ONE.checked_add(&I128::MAX);
155        assert_eq!(result.unwrap(), max_minus_one);
156
157        // lhs = 0
158
159        let result = I128::ZERO.checked_add(&I128::MIN);
160        assert_eq!(result.unwrap(), I128::MIN);
161
162        let result = I128::ZERO.checked_add(&I128::MINUS_ONE);
163        assert_eq!(result.unwrap(), I128::MINUS_ONE);
164
165        let result = I128::ZERO.checked_add(&I128::ZERO);
166        assert_eq!(result.unwrap(), I128::ZERO);
167
168        let result = I128::ZERO.checked_add(&I128::ONE);
169        assert_eq!(result.unwrap(), I128::ONE);
170
171        let result = I128::ZERO.checked_add(&I128::MAX);
172        assert_eq!(result.unwrap(), I128::MAX);
173
174        // lhs = 1
175
176        let result = I128::ONE.checked_add(&I128::MIN);
177        assert_eq!(result.unwrap(), min_plus_one);
178
179        let result = I128::ONE.checked_add(&I128::MINUS_ONE);
180        assert_eq!(result.unwrap(), I128::ZERO);
181
182        let result = I128::ONE.checked_add(&I128::ZERO);
183        assert_eq!(result.unwrap(), I128::ONE);
184
185        let result = I128::ONE.checked_add(&I128::ONE);
186        assert_eq!(result.unwrap(), two);
187
188        let result = I128::ONE.checked_add(&I128::MAX);
189        assert!(bool::from(result.is_none()));
190
191        // lhs = MAX
192
193        let result = I128::MAX.checked_add(&I128::MIN);
194        assert_eq!(result.unwrap(), I128::MINUS_ONE);
195
196        let result = I128::MAX.checked_add(&I128::MINUS_ONE);
197        assert_eq!(result.unwrap(), max_minus_one);
198
199        let result = I128::MAX.checked_add(&I128::ZERO);
200        assert_eq!(result.unwrap(), I128::MAX);
201
202        let result = I128::MAX.checked_add(&I128::ONE);
203        assert!(bool::from(result.is_none()));
204
205        let result = I128::MAX.checked_add(&I128::MAX);
206        assert!(bool::from(result.is_none()));
207    }
208
209    #[test]
210    fn overflowing_add() {
211        let min_plus_one = I128 {
212            0: I128::MIN.0.wrapping_add(&I128::ONE.0),
213        };
214        let max_minus_one = I128 {
215            0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
216        };
217        let two = I128 {
218            0: U128::from(2u32),
219        };
220
221        // lhs = MIN
222
223        let (_val, overflow) = I128::MIN.overflowing_add(&I128::MIN);
224        assert_eq!(overflow, ConstChoice::TRUE);
225
226        let (_val, overflow) = I128::MIN.overflowing_add(&I128::MINUS_ONE);
227        assert_eq!(overflow, ConstChoice::TRUE);
228
229        let (val, overflow) = I128::MIN.overflowing_add(&I128::ZERO);
230        assert_eq!(overflow, ConstChoice::FALSE);
231        assert_eq!(val, I128::MIN);
232
233        let (val, overflow) = I128::MIN.overflowing_add(&I128::ONE);
234        assert_eq!(overflow, ConstChoice::FALSE);
235        assert_eq!(val, min_plus_one);
236
237        let (val, overflow) = I128::MIN.overflowing_add(&I128::MAX);
238        assert_eq!(overflow, ConstChoice::FALSE);
239        assert_eq!(val, I128::MINUS_ONE);
240
241        // lhs = -1
242
243        let (_val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MIN);
244        assert_eq!(overflow, ConstChoice::TRUE);
245
246        let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MINUS_ONE);
247        assert_eq!(overflow, ConstChoice::FALSE);
248        assert_eq!(val, two.wrapping_neg());
249
250        let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::ZERO);
251        assert_eq!(overflow, ConstChoice::FALSE);
252        assert_eq!(val, I128::MINUS_ONE);
253
254        let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::ONE);
255        assert_eq!(overflow, ConstChoice::FALSE);
256        assert_eq!(val, I128::ZERO);
257
258        let (val, overflow) = I128::MINUS_ONE.overflowing_add(&I128::MAX);
259        assert_eq!(overflow, ConstChoice::FALSE);
260        assert_eq!(val, max_minus_one);
261
262        // lhs = 0
263
264        let (val, overflow) = I128::ZERO.overflowing_add(&I128::MIN);
265        assert_eq!(overflow, ConstChoice::FALSE);
266        assert_eq!(val, I128::MIN);
267
268        let (val, overflow) = I128::ZERO.overflowing_add(&I128::MINUS_ONE);
269        assert_eq!(overflow, ConstChoice::FALSE);
270        assert_eq!(val, I128::MINUS_ONE);
271
272        let (val, overflow) = I128::ZERO.overflowing_add(&I128::ZERO);
273        assert_eq!(overflow, ConstChoice::FALSE);
274        assert_eq!(val, I128::ZERO);
275
276        let (val, overflow) = I128::ZERO.overflowing_add(&I128::ONE);
277        assert_eq!(overflow, ConstChoice::FALSE);
278        assert_eq!(val, I128::ONE);
279
280        let (val, overflow) = I128::ZERO.overflowing_add(&I128::MAX);
281        assert_eq!(overflow, ConstChoice::FALSE);
282        assert_eq!(val, I128::MAX);
283
284        // lhs = 1
285
286        let (val, overflow) = I128::ONE.overflowing_add(&I128::MIN);
287        assert_eq!(overflow, ConstChoice::FALSE);
288        assert_eq!(val, min_plus_one);
289
290        let (val, overflow) = I128::ONE.overflowing_add(&I128::MINUS_ONE);
291        assert_eq!(overflow, ConstChoice::FALSE);
292        assert_eq!(val, I128::ZERO);
293
294        let (val, overflow) = I128::ONE.overflowing_add(&I128::ZERO);
295        assert_eq!(overflow, ConstChoice::FALSE);
296        assert_eq!(val, I128::ONE);
297
298        let (val, overflow) = I128::ONE.overflowing_add(&I128::ONE);
299        assert_eq!(overflow, ConstChoice::FALSE);
300        assert_eq!(val, two);
301
302        let (_val, overflow) = I128::ONE.overflowing_add(&I128::MAX);
303        assert_eq!(overflow, ConstChoice::TRUE);
304
305        // lhs = MAX
306
307        let (val, overflow) = I128::MAX.overflowing_add(&I128::MIN);
308        assert_eq!(overflow, ConstChoice::FALSE);
309        assert_eq!(val, I128::MINUS_ONE);
310
311        let (val, overflow) = I128::MAX.overflowing_add(&I128::MINUS_ONE);
312        assert_eq!(overflow, ConstChoice::FALSE);
313        assert_eq!(val, max_minus_one);
314
315        let (val, overflow) = I128::MAX.overflowing_add(&I128::ZERO);
316        assert_eq!(overflow, ConstChoice::FALSE);
317        assert_eq!(val, I128::MAX);
318
319        let (_val, overflow) = I128::MAX.overflowing_add(&I128::ONE);
320        assert_eq!(overflow, ConstChoice::TRUE);
321
322        let (_val, overflow) = I128::MAX.overflowing_add(&I128::MAX);
323        assert_eq!(overflow, ConstChoice::TRUE);
324    }
325}