crypto_bigint/limb/
add.rs

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