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