crypto_bigint/uint/
add.rs

1//! [`UInt`] addition operations.
2
3use crate::{Checked, CheckedAdd, Limb, UInt, Wrapping, 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
28        if overflow.0 == 0 {
29            res
30        } else {
31            Self::MAX
32        }
33    }
34
35    /// Perform wrapping addition, discarding overflow.
36    pub const fn wrapping_add(&self, rhs: &Self) -> Self {
37        self.adc(rhs, Limb::ZERO).0
38    }
39}
40
41impl<const LIMBS: usize> CheckedAdd<&UInt<LIMBS>> for UInt<LIMBS> {
42    type Output = Self;
43
44    fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
45        let (result, carry) = self.adc(rhs, Limb::ZERO);
46        CtOption::new(result, carry.is_zero())
47    }
48}
49
50impl<const LIMBS: usize> Add for Wrapping<UInt<LIMBS>> {
51    type Output = Self;
52
53    fn add(self, rhs: Self) -> Wrapping<UInt<LIMBS>> {
54        Wrapping(self.0.wrapping_add(&rhs.0))
55    }
56}
57
58impl<const LIMBS: usize> Add<&Wrapping<UInt<LIMBS>>> for Wrapping<UInt<LIMBS>> {
59    type Output = Wrapping<UInt<LIMBS>>;
60
61    fn add(self, rhs: &Wrapping<UInt<LIMBS>>) -> Wrapping<UInt<LIMBS>> {
62        Wrapping(self.0.wrapping_add(&rhs.0))
63    }
64}
65
66impl<const LIMBS: usize> Add<Wrapping<UInt<LIMBS>>> for &Wrapping<UInt<LIMBS>> {
67    type Output = Wrapping<UInt<LIMBS>>;
68
69    fn add(self, rhs: Wrapping<UInt<LIMBS>>) -> Wrapping<UInt<LIMBS>> {
70        Wrapping(self.0.wrapping_add(&rhs.0))
71    }
72}
73
74impl<const LIMBS: usize> Add<&Wrapping<UInt<LIMBS>>> for &Wrapping<UInt<LIMBS>> {
75    type Output = Wrapping<UInt<LIMBS>>;
76
77    fn add(self, rhs: &Wrapping<UInt<LIMBS>>) -> Wrapping<UInt<LIMBS>> {
78        Wrapping(self.0.wrapping_add(&rhs.0))
79    }
80}
81
82impl<const LIMBS: usize> AddAssign for Wrapping<UInt<LIMBS>> {
83    fn add_assign(&mut self, other: Self) {
84        *self = *self + other;
85    }
86}
87
88impl<const LIMBS: usize> AddAssign<&Wrapping<UInt<LIMBS>>> for Wrapping<UInt<LIMBS>> {
89    fn add_assign(&mut self, other: &Self) {
90        *self = *self + other;
91    }
92}
93
94impl<const LIMBS: usize> Add for Checked<UInt<LIMBS>> {
95    type Output = Self;
96
97    fn add(self, rhs: Self) -> Checked<UInt<LIMBS>> {
98        Checked(
99            self.0
100                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
101        )
102    }
103}
104
105impl<const LIMBS: usize> Add<&Checked<UInt<LIMBS>>> for Checked<UInt<LIMBS>> {
106    type Output = Checked<UInt<LIMBS>>;
107
108    fn add(self, rhs: &Checked<UInt<LIMBS>>) -> Checked<UInt<LIMBS>> {
109        Checked(
110            self.0
111                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
112        )
113    }
114}
115
116impl<const LIMBS: usize> Add<Checked<UInt<LIMBS>>> for &Checked<UInt<LIMBS>> {
117    type Output = Checked<UInt<LIMBS>>;
118
119    fn add(self, rhs: Checked<UInt<LIMBS>>) -> Checked<UInt<LIMBS>> {
120        Checked(
121            self.0
122                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
123        )
124    }
125}
126
127impl<const LIMBS: usize> Add<&Checked<UInt<LIMBS>>> for &Checked<UInt<LIMBS>> {
128    type Output = Checked<UInt<LIMBS>>;
129
130    fn add(self, rhs: &Checked<UInt<LIMBS>>) -> Checked<UInt<LIMBS>> {
131        Checked(
132            self.0
133                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
134        )
135    }
136}
137
138impl<const LIMBS: usize> AddAssign for Checked<UInt<LIMBS>> {
139    fn add_assign(&mut self, other: Self) {
140        *self = *self + other;
141    }
142}
143
144impl<const LIMBS: usize> AddAssign<&Checked<UInt<LIMBS>>> for Checked<UInt<LIMBS>> {
145    fn add_assign(&mut self, other: &Self) {
146        *self = *self + other;
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use crate::{CheckedAdd, Limb, U128};
153
154    #[test]
155    fn adc_no_carry() {
156        let (res, carry) = U128::ZERO.adc(&U128::ONE, Limb::ZERO);
157        assert_eq!(res, U128::ONE);
158        assert_eq!(carry, Limb::ZERO);
159    }
160
161    #[test]
162    fn adc_with_carry() {
163        let (res, carry) = U128::MAX.adc(&U128::ONE, Limb::ZERO);
164        assert_eq!(res, U128::ZERO);
165        assert_eq!(carry, Limb::ONE);
166    }
167
168    #[test]
169    fn wrapping_add_no_carry() {
170        assert_eq!(U128::ZERO.wrapping_add(&U128::ONE), U128::ONE);
171    }
172
173    #[test]
174    fn wrapping_add_with_carry() {
175        assert_eq!(U128::MAX.wrapping_add(&U128::ONE), U128::ZERO);
176    }
177
178    #[test]
179    fn checked_add_ok() {
180        let result = U128::ZERO.checked_add(&U128::ONE);
181        assert_eq!(result.unwrap(), U128::ONE);
182    }
183
184    #[test]
185    fn checked_add_overflow() {
186        let result = U128::MAX.checked_add(&U128::ONE);
187        assert!(!bool::from(result.is_some()));
188    }
189}