crypto_bigint/uint/
add.rs1use crate::{Checked, CheckedAdd, ConstChoice, Limb, Uint, Wrapping, WrappingAdd, Zero};
4use core::ops::{Add, AddAssign};
5use subtle::CtOption;
6
7impl<const LIMBS: usize> Uint<LIMBS> {
8 #[inline(always)]
10 pub const fn adc(&self, rhs: &Self, mut carry: Limb) -> (Self, Limb) {
11 let mut limbs = [Limb::ZERO; LIMBS];
12 let mut i = 0;
13
14 while i < LIMBS {
15 let (w, c) = self.limbs[i].adc(rhs.limbs[i], carry);
16 limbs[i] = w;
17 carry = c;
18 i += 1;
19 }
20
21 (Self { limbs }, carry)
22 }
23
24 pub const fn saturating_add(&self, rhs: &Self) -> Self {
26 let (res, overflow) = self.adc(rhs, Limb::ZERO);
27 Self::select(&res, &Self::MAX, ConstChoice::from_word_lsb(overflow.0))
28 }
29
30 pub const fn wrapping_add(&self, rhs: &Self) -> Self {
32 self.adc(rhs, Limb::ZERO).0
33 }
34}
35
36impl<const LIMBS: usize> Add for Uint<LIMBS> {
37 type Output = Self;
38
39 fn add(self, rhs: Self) -> Self {
40 self.add(&rhs)
41 }
42}
43
44impl<const LIMBS: usize> Add<&Uint<LIMBS>> for Uint<LIMBS> {
45 type Output = Self;
46
47 fn add(self, rhs: &Self) -> Self {
48 self.checked_add(rhs)
49 .expect("attempted to add with overflow")
50 }
51}
52
53impl<const LIMBS: usize> AddAssign for Uint<LIMBS> {
54 fn add_assign(&mut self, other: Self) {
55 *self += &other;
56 }
57}
58
59impl<const LIMBS: usize> AddAssign<&Uint<LIMBS>> for Uint<LIMBS> {
60 fn add_assign(&mut self, other: &Self) {
61 *self = *self + other;
62 }
63}
64
65impl<const LIMBS: usize> AddAssign for Wrapping<Uint<LIMBS>> {
66 fn add_assign(&mut self, other: Self) {
67 *self = *self + other;
68 }
69}
70
71impl<const LIMBS: usize> AddAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
72 fn add_assign(&mut self, other: &Self) {
73 *self = *self + other;
74 }
75}
76
77impl<const LIMBS: usize> AddAssign for Checked<Uint<LIMBS>> {
78 fn add_assign(&mut self, other: Self) {
79 *self = *self + other;
80 }
81}
82
83impl<const LIMBS: usize> AddAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
84 fn add_assign(&mut self, other: &Self) {
85 *self = *self + other;
86 }
87}
88
89impl<const LIMBS: usize> CheckedAdd for Uint<LIMBS> {
90 fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
91 let (result, carry) = self.adc(rhs, Limb::ZERO);
92 CtOption::new(result, carry.is_zero())
93 }
94}
95
96impl<const LIMBS: usize> WrappingAdd for Uint<LIMBS> {
97 fn wrapping_add(&self, v: &Self) -> Self {
98 self.wrapping_add(v)
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use crate::{CheckedAdd, Limb, U128};
105
106 #[test]
107 fn adc_no_carry() {
108 let (res, carry) = U128::ZERO.adc(&U128::ONE, Limb::ZERO);
109 assert_eq!(res, U128::ONE);
110 assert_eq!(carry, Limb::ZERO);
111 }
112
113 #[test]
114 fn adc_with_carry() {
115 let (res, carry) = U128::MAX.adc(&U128::ONE, Limb::ZERO);
116 assert_eq!(res, U128::ZERO);
117 assert_eq!(carry, Limb::ONE);
118 }
119
120 #[test]
121 fn saturating_add_no_carry() {
122 assert_eq!(U128::ZERO.saturating_add(&U128::ONE), U128::ONE);
123 }
124
125 #[test]
126 fn saturating_add_with_carry() {
127 assert_eq!(U128::MAX.saturating_add(&U128::ONE), U128::MAX);
128 }
129
130 #[test]
131 fn wrapping_add_no_carry() {
132 assert_eq!(U128::ZERO.wrapping_add(&U128::ONE), U128::ONE);
133 }
134
135 #[test]
136 fn wrapping_add_with_carry() {
137 assert_eq!(U128::MAX.wrapping_add(&U128::ONE), U128::ZERO);
138 }
139
140 #[test]
141 fn checked_add_ok() {
142 let result = U128::ZERO.checked_add(&U128::ONE);
143 assert_eq!(result.unwrap(), U128::ONE);
144 }
145
146 #[test]
147 fn checked_add_overflow() {
148 let result = U128::MAX.checked_add(&U128::ONE);
149 assert!(!bool::from(result.is_some()));
150 }
151}