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