Skip to main content

crypto_bigint/limb/
add.rs

1//! Limb addition
2
3use crate::{
4    Add, AddAssign, AddMod, Checked, CheckedAdd, CtOption, Limb, Wrapping, WrappingAdd,
5    primitives::{carrying_add, overflowing_add},
6};
7
8impl Limb {
9    /// Computes `self + rhs + carry`, returning the result along with the new carry.
10    #[deprecated(since = "0.7.0", note = "please use `carrying_add` instead")]
11    #[must_use]
12    pub const fn adc(self, rhs: Limb, carry: Limb) -> (Limb, Limb) {
13        self.carrying_add(rhs, carry)
14    }
15
16    /// Computes `self + rhs + carry`, returning the result along with the new carry.
17    #[inline(always)]
18    #[must_use]
19    pub const fn carrying_add(self, rhs: Limb, carry: Limb) -> (Limb, Limb) {
20        let (res, carry) = carrying_add(self.0, rhs.0, carry.0);
21        (Limb(res), Limb(carry))
22    }
23
24    /// Computes `self + rhs`, returning the result along with the carry.
25    #[inline(always)]
26    #[must_use]
27    pub const fn overflowing_add(self, rhs: Limb) -> (Limb, Limb) {
28        let (res, carry) = overflowing_add(self.0, rhs.0);
29        (Limb(res), Limb(carry))
30    }
31
32    /// Perform saturating addition.
33    #[inline]
34    #[must_use]
35    pub const fn saturating_add(&self, rhs: Self) -> Self {
36        Limb(self.0.saturating_add(rhs.0))
37    }
38
39    /// Perform wrapping addition, discarding overflow.
40    #[inline(always)]
41    #[must_use]
42    pub const fn wrapping_add(&self, rhs: Self) -> Self {
43        Limb(self.0.wrapping_add(rhs.0))
44    }
45}
46
47impl Add for Limb {
48    type Output = Self;
49
50    #[inline]
51    fn add(self, rhs: Self) -> Self {
52        self.checked_add(&rhs)
53            .expect("attempted to add with overflow")
54    }
55}
56
57impl Add<&Self> for Limb {
58    type Output = Self;
59
60    #[inline]
61    fn add(self, rhs: &Self) -> Self {
62        self + *rhs
63    }
64}
65
66impl AddAssign for Limb {
67    #[inline]
68    fn add_assign(&mut self, other: Self) {
69        *self = *self + other;
70    }
71}
72
73impl AddAssign<&Limb> for Limb {
74    #[inline]
75    fn add_assign(&mut self, other: &Self) {
76        *self = *self + *other;
77    }
78}
79
80impl AddAssign for Wrapping<Limb> {
81    #[inline]
82    fn add_assign(&mut self, other: Self) {
83        *self = *self + other;
84    }
85}
86
87impl AddAssign<&Wrapping<Limb>> for Wrapping<Limb> {
88    #[inline]
89    fn add_assign(&mut self, other: &Self) {
90        *self = *self + other;
91    }
92}
93
94impl AddAssign for Checked<Limb> {
95    #[inline]
96    fn add_assign(&mut self, other: Self) {
97        *self = *self + other;
98    }
99}
100
101impl AddAssign<&Checked<Limb>> for Checked<Limb> {
102    #[inline]
103    fn add_assign(&mut self, other: &Self) {
104        *self = *self + other;
105    }
106}
107
108impl CheckedAdd for Limb {
109    #[inline]
110    fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
111        let (result, carry) = self.overflowing_add(*rhs);
112        CtOption::new(result, carry.is_zero())
113    }
114}
115
116impl WrappingAdd for Limb {
117    #[inline]
118    fn wrapping_add(&self, v: &Self) -> Self {
119        self.wrapping_add(*v)
120    }
121}
122
123impl AddMod for Limb {
124    type Output = Self;
125
126    fn add_mod(&self, rhs: &Self, p: &crate::NonZero<Self>) -> Self::Output {
127        let (res, carry) = self.carrying_add(*rhs, Limb::ZERO);
128        let (out, borrow) = res.borrowing_sub(p.get(), Limb::ZERO);
129        let revert = borrow.lsb_to_choice().and(carry.is_zero());
130        Self::select(out, res, revert)
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use crate::{CheckedAdd, Limb};
137
138    #[test]
139    fn add_no_overflow() {
140        assert_eq!(Limb::ZERO + Limb::ONE, Limb::ONE);
141    }
142
143    #[test]
144    #[should_panic]
145    fn add_with_overflow() {
146        let _ = Limb::MAX + Limb::ONE;
147    }
148
149    #[test]
150    fn carrying_add_no_carry() {
151        let (res, carry) = Limb::ZERO.carrying_add(Limb::ONE, Limb::ZERO);
152        assert_eq!(res, Limb::ONE);
153        assert_eq!(carry, Limb::ZERO);
154
155        // TODO(tarcieri): `adc` is deprecated: remove these when the method is removed
156        #[allow(deprecated)]
157        {
158            let (res, carry) = Limb::ZERO.adc(Limb::ONE, Limb::ZERO);
159            assert_eq!(res, Limb::ONE);
160            assert_eq!(carry, Limb::ZERO);
161        }
162    }
163
164    #[test]
165    fn carrying_add_with_carry() {
166        let (res, carry) = Limb::MAX.carrying_add(Limb::ZERO, Limb::ONE);
167        assert_eq!(res, Limb::ZERO);
168        assert_eq!(carry, Limb::ONE);
169
170        // TODO(tarcieri): `adc` is deprecated: remove these when the method is removed
171        #[allow(deprecated)]
172        {
173            let (res, carry) = Limb::MAX.adc(Limb::ZERO, Limb::ONE);
174            assert_eq!(res, Limb::ZERO);
175            assert_eq!(carry, Limb::ONE);
176        }
177    }
178
179    #[test]
180    fn checked_add() {
181        assert_eq!(Limb::ZERO.checked_add(&Limb::ONE).unwrap(), Limb::ONE);
182        assert_eq!(Limb::MAX.checked_add(&Limb::ONE).into_option(), None);
183    }
184
185    #[test]
186    fn overflowing_add_no_carry() {
187        let (res, carry) = Limb::ZERO.overflowing_add(Limb::ONE);
188        assert_eq!(res, Limb::ONE);
189        assert_eq!(carry, Limb::ZERO);
190    }
191
192    #[test]
193    fn overflowing_add_with_carry() {
194        let (res, carry) = Limb::MAX.overflowing_add(Limb::ONE);
195        assert_eq!(res, Limb::ZERO);
196        assert_eq!(carry, Limb::ONE);
197    }
198
199    #[test]
200    fn saturating_add() {
201        assert_eq!(Limb::ZERO.saturating_add(Limb::ONE), Limb::ONE);
202        assert_eq!(Limb::MAX.saturating_add(Limb::ONE), Limb::MAX);
203    }
204
205    #[test]
206    fn wrapping_add_no_carry() {
207        assert_eq!(Limb::ZERO.wrapping_add(Limb::ONE), Limb::ONE);
208    }
209
210    #[test]
211    fn wrapping_add_with_carry() {
212        assert_eq!(Limb::MAX.wrapping_add(Limb::ONE), Limb::ZERO);
213    }
214
215    #[test]
216    fn checked_add_ok() {
217        let result = Limb::ZERO.checked_add(&Limb::ONE);
218        assert_eq!(result.unwrap(), Limb::ONE);
219    }
220
221    #[test]
222    fn checked_add_overflow() {
223        let result = Limb::MAX.checked_add(&Limb::ONE);
224        assert!(!bool::from(result.is_some()));
225    }
226}