crypto_bigint/limb/
add.rs1use crate::{
4 Add, AddAssign, AddMod, Checked, CheckedAdd, CtOption, Limb, Wrapping, WrappingAdd,
5 primitives::{carrying_add, overflowing_add},
6};
7
8impl Limb {
9 #[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 #[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 #[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 #[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 #[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 #[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 #[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}