Skip to main content

crypto_bigint/uint/ref_type/
add.rs

1use super::UintRef;
2use crate::{Choice, Limb};
3
4impl UintRef {
5    /// Perform an in-place carrying add of a limb, returning the carried limb value.
6    #[inline]
7    pub const fn add_assign_limb(&mut self, mut rhs: Limb) -> Limb {
8        let mut i = 0;
9        while i < self.limbs.len() {
10            (self.limbs[i], rhs) = self.limbs[i].overflowing_add(rhs);
11            i += 1;
12        }
13        rhs
14    }
15
16    /// Perform an in-place carrying add of another [`UintRef`], returning the carried limb value.
17    ///
18    /// # Panics
19    /// If `self` is shorter than `rhs`.
20    #[inline]
21    #[track_caller]
22    pub const fn carrying_add_assign(&mut self, rhs: &Self, carry: Limb) -> Limb {
23        self.carrying_add_assign_slice(&rhs.limbs, carry)
24    }
25
26    /// Perform an in-place carrying add of another limb slice, returning the carried limb value.
27    ///
28    /// # Panics
29    /// If `self` is shorter than `rhs`.
30    #[inline]
31    #[track_caller]
32    pub const fn carrying_add_assign_slice(&mut self, rhs: &[Limb], mut carry: Limb) -> Limb {
33        assert!(
34            self.limbs.len() >= rhs.len(),
35            "length mismatch in carrying_add_assign_slice"
36        );
37        let mut i = 0;
38        while i < rhs.len() {
39            (self.limbs[i], carry) = self.limbs[i].carrying_add(rhs[i], carry);
40            i += 1;
41        }
42        while i < self.limbs.len() {
43            (self.limbs[i], carry) = self.limbs[i].overflowing_add(carry);
44            i += 1;
45        }
46        carry
47    }
48
49    /// Perform an in-place carrying add of another limb slice, returning the carried limb value.
50    ///
51    /// # Panics
52    /// If `self` is shorter than `rhs`.
53    #[inline]
54    #[track_caller]
55    pub const fn conditional_add_assign(
56        &mut self,
57        rhs: &Self,
58        carry: Limb,
59        choice: Choice,
60    ) -> Limb {
61        self.conditional_add_assign_slice(rhs.as_limbs(), carry, choice)
62    }
63
64    /// Perform an in-place carrying add of another limb slice, returning the carried limb value.
65    ///
66    /// # Panics
67    /// If `self` is shorter than `rhs`.
68    #[inline]
69    #[track_caller]
70    pub const fn conditional_add_assign_slice(
71        &mut self,
72        rhs: &[Limb],
73        mut carry: Limb,
74        choice: Choice,
75    ) -> Limb {
76        assert!(
77            self.limbs.len() >= rhs.len(),
78            "length mismatch in conditional_add_assign_slice"
79        );
80        let mut i = 0;
81        while i < rhs.len() {
82            (self.limbs[i], carry) =
83                self.limbs[i].carrying_add(Limb::select(Limb::ZERO, rhs[i], choice), carry);
84            i += 1;
85        }
86        while i < self.limbs.len() {
87            (self.limbs[i], carry) = self.limbs[i].overflowing_add(carry);
88            i += 1;
89        }
90        carry
91    }
92
93    /// Perform an in-place carrying add of another [`UintRef`] multiplied by
94    /// a limb, returning the carried limb value.
95    ///
96    /// # Panics
97    /// If `self` is shorter than `rhs`.
98    #[inline]
99    #[track_caller]
100    pub const fn carrying_add_assign_mul_limb(
101        &mut self,
102        rhs: &Self,
103        rhs_mul: Limb,
104        mut carry: Limb,
105    ) -> Limb {
106        assert!(
107            self.limbs.len() >= rhs.limbs.len(),
108            "length mismatch in carrying_add_assign_mul_limb"
109        );
110        let mut i = 0;
111        while i < rhs.limbs.len() {
112            (self.limbs[i], carry) = rhs.limbs[i].carrying_mul_add(rhs_mul, self.limbs[i], carry);
113            i += 1;
114        }
115        self.trailing_mut(i).add_assign_limb(carry)
116    }
117}
118
119#[cfg(test)]
120mod tests {
121    use crate::{Choice, Limb, UintRef, Unsigned};
122
123    #[test]
124    fn carrying_add_assign_mixed() {
125        let mut a = [Limb::MAX];
126        let carry =
127            UintRef::new_mut(&mut a).carrying_add_assign(Limb::ONE.as_uint_ref(), Limb::ZERO);
128        assert_eq!((a, carry), ([Limb::ZERO], Limb::ONE));
129
130        let mut a = [Limb::MAX];
131        let carry = UintRef::new_mut(&mut a).conditional_add_assign(
132            Limb::ONE.as_uint_ref(),
133            Limb::ZERO,
134            Choice::FALSE,
135        );
136        assert_eq!((a, carry), ([Limb::MAX], Limb::ZERO));
137
138        let mut a = [Limb::MAX];
139        let carry = UintRef::new_mut(&mut a).conditional_add_assign(
140            Limb::ONE.as_uint_ref(),
141            Limb::ZERO,
142            Choice::TRUE,
143        );
144        assert_eq!((a, carry), ([Limb::ZERO], Limb::ONE));
145
146        let mut a = [Limb::MAX, Limb::MAX];
147        let carry =
148            UintRef::new_mut(&mut a).carrying_add_assign(Limb::ZERO.as_uint_ref(), Limb::ONE);
149        assert_eq!((a, carry), ([Limb::ZERO, Limb::ZERO], Limb::ONE));
150
151        let mut a = [Limb::MAX, Limb::MAX];
152        let carry = UintRef::new_mut(&mut a).conditional_add_assign(
153            Limb::MAX.as_uint_ref(),
154            Limb::ONE,
155            Choice::TRUE,
156        );
157        assert_eq!((a, carry), ([Limb::MAX, Limb::ZERO], Limb::ONE));
158    }
159}