Skip to main content

crypto_bigint/uint/
bit_and.rs

1//! [`Uint`] bitwise AND operations.
2
3use super::Uint;
4use crate::{BitAnd, BitAndAssign, CtOption, Limb, Wrapping};
5
6impl<const LIMBS: usize> Uint<LIMBS> {
7    /// Computes bitwise `a & b`.
8    #[inline(always)]
9    #[must_use]
10    pub const fn bitand(&self, rhs: &Self) -> Self {
11        let mut limbs = [Limb::ZERO; LIMBS];
12        let mut i = 0;
13
14        while i < LIMBS {
15            limbs[i] = self.limbs[i].bitand(rhs.limbs[i]);
16            i += 1;
17        }
18
19        Self { limbs }
20    }
21
22    /// Perform bitwise `AND` between `self` and the given [`Limb`], performing the `AND` operation
23    /// on every limb of `self`.
24    #[must_use]
25    pub const fn bitand_limb(&self, rhs: Limb) -> Self {
26        let mut limbs = [Limb::ZERO; LIMBS];
27        let mut i = 0;
28
29        while i < LIMBS {
30            limbs[i] = self.limbs[i].bitand(rhs);
31            i += 1;
32        }
33
34        Self { limbs }
35    }
36
37    /// Perform wrapping bitwise `AND`.
38    ///
39    /// There's no way wrapping could ever happen.
40    /// This function exists so that all operations are accounted for in the wrapping operations
41    #[must_use]
42    pub const fn wrapping_and(&self, rhs: &Self) -> Self {
43        self.bitand(rhs)
44    }
45
46    /// Perform checked bitwise `AND`, returning a [`CtOption`] which `is_some` always
47    #[must_use]
48    pub const fn checked_and(&self, rhs: &Self) -> CtOption<Self> {
49        CtOption::some(self.bitand(rhs))
50    }
51}
52
53impl<const LIMBS: usize> BitAnd for Uint<LIMBS> {
54    type Output = Self;
55
56    fn bitand(self, rhs: Self) -> Uint<LIMBS> {
57        self.bitand(&rhs)
58    }
59}
60
61impl<const LIMBS: usize> BitAnd<&Uint<LIMBS>> for Uint<LIMBS> {
62    type Output = Uint<LIMBS>;
63
64    #[allow(clippy::needless_borrow)]
65    fn bitand(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
66        (&self).bitand(rhs)
67    }
68}
69
70impl<const LIMBS: usize> BitAnd<Uint<LIMBS>> for &Uint<LIMBS> {
71    type Output = Uint<LIMBS>;
72
73    fn bitand(self, rhs: Uint<LIMBS>) -> Uint<LIMBS> {
74        self.bitand(&rhs)
75    }
76}
77
78impl<const LIMBS: usize> BitAnd<&Uint<LIMBS>> for &Uint<LIMBS> {
79    type Output = Uint<LIMBS>;
80
81    fn bitand(self, rhs: &Uint<LIMBS>) -> Uint<LIMBS> {
82        self.bitand(rhs)
83    }
84}
85
86impl<const LIMBS: usize> BitAndAssign for Uint<LIMBS> {
87    #[allow(clippy::assign_op_pattern)]
88    fn bitand_assign(&mut self, other: Self) {
89        *self = *self & other;
90    }
91}
92
93impl<const LIMBS: usize> BitAndAssign<&Uint<LIMBS>> for Uint<LIMBS> {
94    #[allow(clippy::assign_op_pattern)]
95    fn bitand_assign(&mut self, other: &Self) {
96        *self = *self & other;
97    }
98}
99
100impl<const LIMBS: usize> BitAnd for Wrapping<Uint<LIMBS>> {
101    type Output = Self;
102
103    fn bitand(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
104        Wrapping(self.0.bitand(&rhs.0))
105    }
106}
107
108impl<const LIMBS: usize> BitAnd<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
109    type Output = Wrapping<Uint<LIMBS>>;
110
111    fn bitand(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
112        Wrapping(self.0.bitand(&rhs.0))
113    }
114}
115
116impl<const LIMBS: usize> BitAnd<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
117    type Output = Wrapping<Uint<LIMBS>>;
118
119    fn bitand(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
120        Wrapping(self.0.bitand(&rhs.0))
121    }
122}
123
124impl<const LIMBS: usize> BitAnd<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
125    type Output = Wrapping<Uint<LIMBS>>;
126
127    fn bitand(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
128        Wrapping(self.0.bitand(&rhs.0))
129    }
130}
131
132impl<const LIMBS: usize> BitAndAssign for Wrapping<Uint<LIMBS>> {
133    #[allow(clippy::assign_op_pattern)]
134    fn bitand_assign(&mut self, other: Self) {
135        *self = *self & other;
136    }
137}
138
139impl<const LIMBS: usize> BitAndAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
140    #[allow(clippy::assign_op_pattern)]
141    fn bitand_assign(&mut self, other: &Self) {
142        *self = *self & other;
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use crate::U128;
149
150    #[test]
151    fn checked_and_ok() {
152        let result = U128::ZERO.checked_and(&U128::ONE);
153        assert_eq!(result.unwrap(), U128::ZERO);
154    }
155
156    #[test]
157    fn overlapping_and_ok() {
158        let result = U128::MAX.wrapping_and(&U128::ONE);
159        assert_eq!(result, U128::ONE);
160    }
161}