1 //! Limb addition 2 3 use super::{Inner, Limb, Wide}; 4 use crate::{Encoding, Wrapping}; 5 use core::ops::{Add, AddAssign}; 6 use subtle::CtOption; 7 8 impl Limb { 9 /// Computes `self + rhs + carry`, returning the result along with the new carry. 10 #[inline(always)] adc(self, rhs: Limb, carry: Limb) -> (Limb, Limb)11 pub const fn adc(self, rhs: Limb, carry: Limb) -> (Limb, Limb) { 12 let a = self.0 as Wide; 13 let b = rhs.0 as Wide; 14 let carry = carry.0 as Wide; 15 let ret = a + b + carry; 16 (Limb(ret as Inner), Limb((ret >> Self::BIT_SIZE) as Inner)) 17 } 18 19 /// Perform wrapping addition, discarding overflow. 20 #[inline(always)] wrapping_add(&self, rhs: Self) -> Self21 pub const fn wrapping_add(&self, rhs: Self) -> Self { 22 Limb(self.0.wrapping_add(rhs.0)) 23 } 24 25 /// Perform checked addition, returning a [`CtOption`] which `is_some` only 26 /// if the operation did not overflow. 27 #[inline] checked_add(&self, rhs: Self) -> CtOption<Self>28 pub fn checked_add(&self, rhs: Self) -> CtOption<Self> { 29 let (result, carry) = self.adc(rhs, Limb::ZERO); 30 CtOption::new(result, carry.is_zero()) 31 } 32 } 33 34 impl Add for Wrapping<Limb> { 35 type Output = Self; 36 add(self, rhs: Self) -> Wrapping<Limb>37 fn add(self, rhs: Self) -> Wrapping<Limb> { 38 Wrapping(self.0.wrapping_add(rhs.0)) 39 } 40 } 41 42 impl Add<&Wrapping<Limb>> for Wrapping<Limb> { 43 type Output = Wrapping<Limb>; 44 add(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb>45 fn add(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> { 46 Wrapping(self.0.wrapping_add(rhs.0)) 47 } 48 } 49 50 impl Add<Wrapping<Limb>> for &Wrapping<Limb> { 51 type Output = Wrapping<Limb>; 52 add(self, rhs: Wrapping<Limb>) -> Wrapping<Limb>53 fn add(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> { 54 Wrapping(self.0.wrapping_add(rhs.0)) 55 } 56 } 57 58 impl Add<&Wrapping<Limb>> for &Wrapping<Limb> { 59 type Output = Wrapping<Limb>; 60 add(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb>61 fn add(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> { 62 Wrapping(self.0.wrapping_add(rhs.0)) 63 } 64 } 65 66 impl AddAssign for Wrapping<Limb> { add_assign(&mut self, other: Self)67 fn add_assign(&mut self, other: Self) { 68 *self = *self + other; 69 } 70 } 71 72 impl AddAssign<&Wrapping<Limb>> for Wrapping<Limb> { add_assign(&mut self, other: &Self)73 fn add_assign(&mut self, other: &Self) { 74 *self = *self + other; 75 } 76 } 77 78 #[cfg(test)] 79 mod tests { 80 use crate::Limb; 81 82 #[test] adc_no_carry()83 fn adc_no_carry() { 84 let (res, carry) = Limb::ZERO.adc(Limb::ONE, Limb::ZERO); 85 assert_eq!(res, Limb::ONE); 86 assert_eq!(carry, Limb::ZERO); 87 } 88 89 #[test] adc_with_carry()90 fn adc_with_carry() { 91 let (res, carry) = Limb::MAX.adc(Limb::ONE, Limb::ZERO); 92 assert_eq!(res, Limb::ZERO); 93 assert_eq!(carry, Limb::ONE); 94 } 95 96 #[test] wrapping_add_no_carry()97 fn wrapping_add_no_carry() { 98 assert_eq!(Limb::ZERO.wrapping_add(Limb::ONE), Limb::ONE); 99 } 100 101 #[test] wrapping_add_with_carry()102 fn wrapping_add_with_carry() { 103 assert_eq!(Limb::MAX.wrapping_add(Limb::ONE), Limb::ZERO); 104 } 105 106 #[test] checked_add_ok()107 fn checked_add_ok() { 108 let result = Limb::ZERO.checked_add(Limb::ONE); 109 assert_eq!(result.unwrap(), Limb::ONE); 110 } 111 112 #[test] checked_add_overflow()113 fn checked_add_overflow() { 114 let result = Limb::MAX.checked_add(Limb::ONE); 115 assert!(!bool::from(result.is_some())); 116 } 117 } 118