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