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