Skip to main content

crypto_bigint/int/
add.rs

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