crypto_bigint/uint/
bit_and.rs

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