crypto_bigint/uint/boxed/
add.rs1use crate::{
4 Add, AddAssign, BoxedUint, CheckedAdd, Choice, CtOption, Limb, U64, U128, UintRef, Wrapping,
5 WrappingAdd,
6};
7use core::cmp;
8
9impl BoxedUint {
10 #[deprecated(since = "0.7.0", note = "please use `carrying_add` instead")]
12 #[must_use]
13 pub fn adc(&self, rhs: &Self, carry: Limb) -> (Self, Limb) {
14 self.carrying_add(rhs, carry)
15 }
16
17 #[inline(always)]
21 #[must_use]
22 pub fn carrying_add(&self, rhs: impl AsRef<UintRef>, carry: Limb) -> (Self, Limb) {
23 let rhs = rhs.as_ref();
24 let precision = cmp::max(self.bits_precision(), rhs.bits_precision());
25 let mut result = Self::zero_with_precision(precision);
26 let carry =
27 result
28 .as_mut_uint_ref()
29 .fold_limbs(self.as_uint_ref(), rhs, carry, Limb::carrying_add);
30 (result, carry)
31 }
32
33 #[deprecated(since = "0.7.0", note = "please use `carrying_add_assign` instead")]
38 pub fn adc_assign(&mut self, rhs: impl AsRef<[Limb]>, carry: Limb) -> Limb {
39 self.carrying_add_assign(UintRef::new(rhs.as_ref()), carry)
40 }
41
42 #[inline(always)]
47 #[track_caller]
48 pub(crate) fn carrying_add_assign(&mut self, rhs: impl AsRef<UintRef>, carry: Limb) -> Limb {
49 let rhs = rhs.as_ref();
50 assert!(rhs.nlimbs() <= self.nlimbs());
51
52 self.as_mut_uint_ref()
53 .fold_limbs_assign(rhs, carry, Limb::carrying_add)
54 }
55
56 #[must_use]
59 pub fn concatenating_add(&self, rhs: impl AsRef<UintRef>) -> Self {
60 let rhs = rhs.as_ref();
61 let bits = cmp::max(self.bits_precision(), rhs.bits_precision()) + 1;
62 let mut result = Self::zero_with_precision(bits);
63 let overflow = result.as_mut_uint_ref().fold_limbs(
64 self.as_uint_ref(),
65 rhs,
66 Limb::ZERO,
67 Limb::carrying_add,
68 );
69 debug_assert_eq!(overflow, Limb::ZERO);
71 result
72 }
73
74 #[must_use]
79 pub fn overflowing_add(&self, rhs: impl AsRef<UintRef>) -> (Self, Choice) {
80 let rhs = rhs.as_ref();
81 let nlimbs = cmp::min(self.nlimbs(), rhs.nlimbs());
82 let (rhs, rhs_over) = rhs.split_at(nlimbs);
83 let (ret, carry) = self.carrying_add(rhs, Limb::ZERO);
84 (ret, carry.is_nonzero().or(rhs_over.is_nonzero()))
85 }
86
87 pub fn overflowing_add_assign(&mut self, rhs: impl AsRef<UintRef>) -> Choice {
91 let rhs = rhs.as_ref();
92 let nlimbs = cmp::min(self.nlimbs(), rhs.nlimbs());
93 let (rhs, rhs_over) = rhs.split_at(nlimbs);
94 let carry = self.carrying_add_assign(rhs, Limb::ZERO);
95 carry.is_nonzero().or(rhs_over.is_nonzero())
96 }
97
98 #[must_use]
100 pub fn wrapping_add(&self, rhs: impl AsRef<UintRef>) -> Self {
101 let rhs = rhs.as_ref();
102 let nlimbs = cmp::min(self.nlimbs(), rhs.nlimbs());
103 self.carrying_add(rhs.leading(nlimbs), Limb::ZERO).0
104 }
105
106 pub fn wrapping_add_assign(&mut self, rhs: impl AsRef<UintRef>) {
108 let rhs = rhs.as_ref();
109 let nlimbs = cmp::min(self.nlimbs(), rhs.nlimbs());
110 self.carrying_add_assign(rhs.leading(nlimbs), Limb::ZERO);
111 }
112
113 pub(crate) fn conditional_carrying_add_assign(&mut self, rhs: &Self, choice: Choice) -> Choice {
116 self.as_mut_uint_ref()
117 .conditional_add_assign(rhs.as_uint_ref(), Limb::ZERO, choice)
118 .lsb_to_choice()
119 }
120}
121
122impl<Rhs: AsRef<UintRef>> Add<Rhs> for BoxedUint {
123 type Output = Self;
124
125 fn add(self, rhs: Rhs) -> Self {
126 Add::add(&self, rhs)
127 }
128}
129
130impl<Rhs: AsRef<UintRef>> Add<Rhs> for &BoxedUint {
131 type Output = BoxedUint;
132
133 fn add(self, rhs: Rhs) -> BoxedUint {
134 let (res, overflow) = self.overflowing_add(rhs);
135 assert!(overflow.not().to_bool(), "attempted to add with overflow");
136 res
137 }
138}
139
140impl<Rhs: AsRef<UintRef>> AddAssign<Rhs> for BoxedUint {
141 fn add_assign(&mut self, rhs: Rhs) {
142 let overflow = self.overflowing_add_assign(rhs);
143 assert!(overflow.not().to_bool(), "attempted to add with overflow");
144 }
145}
146
147impl<Rhs: AsRef<UintRef>> AddAssign<Rhs> for Wrapping<BoxedUint> {
148 fn add_assign(&mut self, other: Rhs) {
149 self.0.wrapping_add_assign(other);
150 }
151}
152
153impl<Rhs: AsRef<UintRef>> CheckedAdd<Rhs> for BoxedUint {
154 fn checked_add(&self, rhs: &Rhs) -> CtOption<Self> {
155 let (result, overflow) = self.overflowing_add(rhs);
156 CtOption::new(result, overflow.not())
157 }
158}
159
160impl WrappingAdd for BoxedUint {
161 fn wrapping_add(&self, v: &Self) -> Self {
162 self.wrapping_add(v)
163 }
164}
165
166macro_rules! impl_add_primitive {
167 ($($primitive:ty),+) => {
168 $(
169 impl Add<$primitive> for BoxedUint {
170 type Output = <Self as Add<U64>>::Output;
171
172 #[inline]
173 fn add(self, rhs: $primitive) -> Self::Output {
174 self + U64::from(rhs)
175 }
176 }
177
178 impl Add<$primitive> for &BoxedUint {
179 type Output = <Self as Add<U64>>::Output;
180
181 #[inline]
182 fn add(self, rhs: $primitive) -> Self::Output {
183 self + U64::from(rhs)
184 }
185 }
186
187 impl AddAssign<$primitive> for BoxedUint {
188 fn add_assign(&mut self, rhs: $primitive) {
189 *self += U64::from(rhs);
190 }
191 }
192 )+
193 };
194}
195
196impl_add_primitive!(u8, u16, u32, u64);
197
198impl Add<u128> for BoxedUint {
199 type Output = BoxedUint;
200
201 #[inline]
202 fn add(self, rhs: u128) -> BoxedUint {
203 self + U128::from(rhs)
204 }
205}
206
207impl Add<u128> for &BoxedUint {
208 type Output = BoxedUint;
209
210 #[inline]
211 fn add(self, rhs: u128) -> BoxedUint {
212 self + U128::from(rhs)
213 }
214}
215
216impl AddAssign<u128> for BoxedUint {
217 fn add_assign(&mut self, rhs: u128) {
218 *self += U128::from(rhs);
219 }
220}
221
222#[cfg(test)]
223#[allow(clippy::unwrap_used)]
224mod tests {
225 use super::{BoxedUint, CheckedAdd, Limb, UintRef, Wrapping};
226 use crate::Resize;
227
228 #[test]
229 fn add_assign() {
230 let mut h = BoxedUint::one().resize(1024);
231 h += BoxedUint::one();
232 assert_eq!(h, BoxedUint::from(2u8));
233 }
234
235 #[test]
236 fn add_with_u32_rhs() {
237 let a = BoxedUint::from(1u64);
238 let b = a + u32::MAX;
239 assert_eq!(b, BoxedUint::from(0x100000000u64));
240 }
241
242 #[test]
243 fn carrying_add_no_carry() {
244 let (res, carry) = BoxedUint::zero().carrying_add(BoxedUint::one(), Limb::ZERO);
245 assert_eq!(res, BoxedUint::one());
246 assert_eq!(carry, Limb::ZERO);
247 }
248
249 #[test]
250 fn carrying_add_with_carry() {
251 let (res, carry) = BoxedUint::max(Limb::BITS).carrying_add(BoxedUint::one(), Limb::ZERO);
252 assert_eq!(res, BoxedUint::zero());
253 assert_eq!(carry, Limb::ONE);
254 }
255
256 #[test]
257 fn checked_add_ok() {
258 let result = BoxedUint::zero().checked_add(&BoxedUint::one());
259 assert_eq!(result.unwrap(), BoxedUint::one());
260 }
261
262 #[test]
263 fn checked_add_overflow() {
264 let result = BoxedUint::max(Limb::BITS).checked_add(&BoxedUint::one());
265 assert!(!bool::from(result.is_some()));
266 }
267
268 #[test]
269 fn concatenating_add() {
270 let result = BoxedUint::max(Limb::BITS).concatenating_add(BoxedUint::one());
271 assert_eq!(result.as_limbs(), &[Limb::ZERO, Limb::ONE]);
272 }
273
274 #[test]
275 fn overflowing_add() {
276 let one = BoxedUint::one();
277 let (ret, overflow) = one.overflowing_add(&one);
278 assert_eq!(ret, &one + &one);
279 assert!(!overflow.to_bool());
280
281 let (ret, overflow) = BoxedUint::max(2 * Limb::BITS).overflowing_add(&one);
282 assert!(ret.is_zero().to_bool());
283 assert!(overflow.to_bool());
284 }
285
286 #[test]
287 fn wrapping_add() {
288 let ret = BoxedUint::one().wrapping_add(Limb::ONE);
289 assert_eq!(ret, BoxedUint::from(2u8));
290
291 let mut ret = Wrapping(BoxedUint::max(2 * Limb::BITS));
292 ret += Wrapping(Limb::ONE);
293 assert!(ret.0.is_zero_vartime());
294 }
295
296 #[test]
297 fn add_uintref() {
298 let a = BoxedUint::from(1234567890u64);
299 let b = UintRef::new(&[Limb(456), Limb(0)]);
300 assert_eq!(
301 a.carrying_add(b, Limb::ZERO).0,
302 BoxedUint::from(1234568346u64)
303 );
304 }
305}