crypto_bigint/uint/
add.rs
1use crate::{Checked, CheckedAdd, Limb, UInt, Wrapping, 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
28 if overflow.0 == 0 {
29 res
30 } else {
31 Self::MAX
32 }
33 }
34
35 pub const fn wrapping_add(&self, rhs: &Self) -> Self {
37 self.adc(rhs, Limb::ZERO).0
38 }
39}
40
41impl<const LIMBS: usize> CheckedAdd<&UInt<LIMBS>> for UInt<LIMBS> {
42 type Output = Self;
43
44 fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
45 let (result, carry) = self.adc(rhs, Limb::ZERO);
46 CtOption::new(result, carry.is_zero())
47 }
48}
49
50impl<const LIMBS: usize> Add for Wrapping<UInt<LIMBS>> {
51 type Output = Self;
52
53 fn add(self, rhs: Self) -> Wrapping<UInt<LIMBS>> {
54 Wrapping(self.0.wrapping_add(&rhs.0))
55 }
56}
57
58impl<const LIMBS: usize> Add<&Wrapping<UInt<LIMBS>>> for Wrapping<UInt<LIMBS>> {
59 type Output = Wrapping<UInt<LIMBS>>;
60
61 fn add(self, rhs: &Wrapping<UInt<LIMBS>>) -> Wrapping<UInt<LIMBS>> {
62 Wrapping(self.0.wrapping_add(&rhs.0))
63 }
64}
65
66impl<const LIMBS: usize> Add<Wrapping<UInt<LIMBS>>> for &Wrapping<UInt<LIMBS>> {
67 type Output = Wrapping<UInt<LIMBS>>;
68
69 fn add(self, rhs: Wrapping<UInt<LIMBS>>) -> Wrapping<UInt<LIMBS>> {
70 Wrapping(self.0.wrapping_add(&rhs.0))
71 }
72}
73
74impl<const LIMBS: usize> Add<&Wrapping<UInt<LIMBS>>> for &Wrapping<UInt<LIMBS>> {
75 type Output = Wrapping<UInt<LIMBS>>;
76
77 fn add(self, rhs: &Wrapping<UInt<LIMBS>>) -> Wrapping<UInt<LIMBS>> {
78 Wrapping(self.0.wrapping_add(&rhs.0))
79 }
80}
81
82impl<const LIMBS: usize> AddAssign for Wrapping<UInt<LIMBS>> {
83 fn add_assign(&mut self, other: Self) {
84 *self = *self + other;
85 }
86}
87
88impl<const LIMBS: usize> AddAssign<&Wrapping<UInt<LIMBS>>> for Wrapping<UInt<LIMBS>> {
89 fn add_assign(&mut self, other: &Self) {
90 *self = *self + other;
91 }
92}
93
94impl<const LIMBS: usize> Add for Checked<UInt<LIMBS>> {
95 type Output = Self;
96
97 fn add(self, rhs: Self) -> Checked<UInt<LIMBS>> {
98 Checked(
99 self.0
100 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
101 )
102 }
103}
104
105impl<const LIMBS: usize> Add<&Checked<UInt<LIMBS>>> for Checked<UInt<LIMBS>> {
106 type Output = Checked<UInt<LIMBS>>;
107
108 fn add(self, rhs: &Checked<UInt<LIMBS>>) -> Checked<UInt<LIMBS>> {
109 Checked(
110 self.0
111 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
112 )
113 }
114}
115
116impl<const LIMBS: usize> Add<Checked<UInt<LIMBS>>> for &Checked<UInt<LIMBS>> {
117 type Output = Checked<UInt<LIMBS>>;
118
119 fn add(self, rhs: Checked<UInt<LIMBS>>) -> Checked<UInt<LIMBS>> {
120 Checked(
121 self.0
122 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
123 )
124 }
125}
126
127impl<const LIMBS: usize> Add<&Checked<UInt<LIMBS>>> for &Checked<UInt<LIMBS>> {
128 type Output = Checked<UInt<LIMBS>>;
129
130 fn add(self, rhs: &Checked<UInt<LIMBS>>) -> Checked<UInt<LIMBS>> {
131 Checked(
132 self.0
133 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_add(&rhs))),
134 )
135 }
136}
137
138impl<const LIMBS: usize> AddAssign for Checked<UInt<LIMBS>> {
139 fn add_assign(&mut self, other: Self) {
140 *self = *self + other;
141 }
142}
143
144impl<const LIMBS: usize> AddAssign<&Checked<UInt<LIMBS>>> for Checked<UInt<LIMBS>> {
145 fn add_assign(&mut self, other: &Self) {
146 *self = *self + other;
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use crate::{CheckedAdd, Limb, U128};
153
154 #[test]
155 fn adc_no_carry() {
156 let (res, carry) = U128::ZERO.adc(&U128::ONE, Limb::ZERO);
157 assert_eq!(res, U128::ONE);
158 assert_eq!(carry, Limb::ZERO);
159 }
160
161 #[test]
162 fn adc_with_carry() {
163 let (res, carry) = U128::MAX.adc(&U128::ONE, Limb::ZERO);
164 assert_eq!(res, U128::ZERO);
165 assert_eq!(carry, Limb::ONE);
166 }
167
168 #[test]
169 fn wrapping_add_no_carry() {
170 assert_eq!(U128::ZERO.wrapping_add(&U128::ONE), U128::ONE);
171 }
172
173 #[test]
174 fn wrapping_add_with_carry() {
175 assert_eq!(U128::MAX.wrapping_add(&U128::ONE), U128::ZERO);
176 }
177
178 #[test]
179 fn checked_add_ok() {
180 let result = U128::ZERO.checked_add(&U128::ONE);
181 assert_eq!(result.unwrap(), U128::ONE);
182 }
183
184 #[test]
185 fn checked_add_overflow() {
186 let result = U128::MAX.checked_add(&U128::ONE);
187 assert!(!bool::from(result.is_some()));
188 }
189}