crypto_bigint/limb/
add.rs

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