crypto_bigint/uint/
add.rs

1//! [`Uint`] addition operations.
2
3use crate::{Checked, CheckedAdd, ConstChoice, Limb, Uint, Wrapping, WrappingAdd, Zero};
4use core::ops::{Add, AddAssign};
5use subtle::CtOption;
6
7impl<const LIMBS: usize> Uint<LIMBS> {
8    /// Computes `a + b + carry`, returning the result along with the new carry.
9    #[inline(always)]
10    pub const fn adc(&self, rhs: &Self, mut carry: Limb) -> (Self, Limb) {
11        let mut limbs = [Limb::ZERO; LIMBS];
12        let mut i = 0;
13
14        while i < LIMBS {
15            let (w, c) = self.limbs[i].adc(rhs.limbs[i], carry);
16            limbs[i] = w;
17            carry = c;
18            i += 1;
19        }
20
21        (Self { limbs }, carry)
22    }
23
24    /// Perform saturating addition, returning `MAX` on overflow.
25    pub const fn saturating_add(&self, rhs: &Self) -> Self {
26        let (res, overflow) = self.adc(rhs, Limb::ZERO);
27        Self::select(&res, &Self::MAX, ConstChoice::from_word_lsb(overflow.0))
28    }
29
30    /// Perform wrapping addition, discarding overflow.
31    pub const fn wrapping_add(&self, rhs: &Self) -> Self {
32        self.adc(rhs, Limb::ZERO).0
33    }
34}
35
36impl<const LIMBS: usize> Add for Uint<LIMBS> {
37    type Output = Self;
38
39    fn add(self, rhs: Self) -> Self {
40        self.add(&rhs)
41    }
42}
43
44impl<const LIMBS: usize> Add<&Uint<LIMBS>> for Uint<LIMBS> {
45    type Output = Self;
46
47    fn add(self, rhs: &Self) -> Self {
48        self.checked_add(rhs)
49            .expect("attempted to add with overflow")
50    }
51}
52
53impl<const LIMBS: usize> AddAssign for Uint<LIMBS> {
54    fn add_assign(&mut self, other: Self) {
55        *self += &other;
56    }
57}
58
59impl<const LIMBS: usize> AddAssign<&Uint<LIMBS>> for Uint<LIMBS> {
60    fn add_assign(&mut self, other: &Self) {
61        *self = *self + other;
62    }
63}
64
65impl<const LIMBS: usize> AddAssign for Wrapping<Uint<LIMBS>> {
66    fn add_assign(&mut self, other: Self) {
67        *self = *self + other;
68    }
69}
70
71impl<const LIMBS: usize> AddAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
72    fn add_assign(&mut self, other: &Self) {
73        *self = *self + other;
74    }
75}
76
77impl<const LIMBS: usize> AddAssign for Checked<Uint<LIMBS>> {
78    fn add_assign(&mut self, other: Self) {
79        *self = *self + other;
80    }
81}
82
83impl<const LIMBS: usize> AddAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
84    fn add_assign(&mut self, other: &Self) {
85        *self = *self + other;
86    }
87}
88
89impl<const LIMBS: usize> CheckedAdd for Uint<LIMBS> {
90    fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
91        let (result, carry) = self.adc(rhs, Limb::ZERO);
92        CtOption::new(result, carry.is_zero())
93    }
94}
95
96impl<const LIMBS: usize> WrappingAdd for Uint<LIMBS> {
97    fn wrapping_add(&self, v: &Self) -> Self {
98        self.wrapping_add(v)
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use crate::{CheckedAdd, Limb, U128};
105
106    #[test]
107    fn adc_no_carry() {
108        let (res, carry) = U128::ZERO.adc(&U128::ONE, Limb::ZERO);
109        assert_eq!(res, U128::ONE);
110        assert_eq!(carry, Limb::ZERO);
111    }
112
113    #[test]
114    fn adc_with_carry() {
115        let (res, carry) = U128::MAX.adc(&U128::ONE, Limb::ZERO);
116        assert_eq!(res, U128::ZERO);
117        assert_eq!(carry, Limb::ONE);
118    }
119
120    #[test]
121    fn saturating_add_no_carry() {
122        assert_eq!(U128::ZERO.saturating_add(&U128::ONE), U128::ONE);
123    }
124
125    #[test]
126    fn saturating_add_with_carry() {
127        assert_eq!(U128::MAX.saturating_add(&U128::ONE), U128::MAX);
128    }
129
130    #[test]
131    fn wrapping_add_no_carry() {
132        assert_eq!(U128::ZERO.wrapping_add(&U128::ONE), U128::ONE);
133    }
134
135    #[test]
136    fn wrapping_add_with_carry() {
137        assert_eq!(U128::MAX.wrapping_add(&U128::ONE), U128::ZERO);
138    }
139
140    #[test]
141    fn checked_add_ok() {
142        let result = U128::ZERO.checked_add(&U128::ONE);
143        assert_eq!(result.unwrap(), U128::ONE);
144    }
145
146    #[test]
147    fn checked_add_overflow() {
148        let result = U128::MAX.checked_add(&U128::ONE);
149        assert!(!bool::from(result.is_some()));
150    }
151}