Skip to main content

crypto_bigint/uint/boxed/
bits.rs

1//! Bit manipulation functions.
2
3use crate::{BitOps, BoxedUint, Choice, Limb};
4
5impl BoxedUint {
6    /// Get the value of the bit at position `index`, as a truthy or falsy `Choice`.
7    /// Returns the falsy value for indices out of range.
8    #[must_use]
9    pub fn bit(&self, index: u32) -> Choice {
10        self.as_uint_ref().bit(index)
11    }
12
13    /// Returns `true` if the bit at position `index` is set, `false` otherwise.
14    ///
15    /// # Remarks
16    /// This operation is variable time with respect to `index` only.
17    #[inline(always)]
18    #[must_use]
19    pub const fn bit_vartime(&self, index: u32) -> bool {
20        self.as_uint_ref().bit_vartime(index)
21    }
22
23    /// Calculate the number of bits needed to represent this number, i.e. the index of the highest
24    /// set bit.
25    ///
26    /// Use [`BoxedUint::bits_precision`] to get the total capacity of this integer.
27    #[must_use]
28    pub fn bits(&self) -> u32 {
29        self.bits_precision() - self.leading_zeros()
30    }
31
32    /// Calculate the number of bits needed to represent this number in variable-time with respect
33    /// to `self`.
34    #[must_use]
35    pub fn bits_vartime(&self) -> u32 {
36        self.as_uint_ref().bits_vartime()
37    }
38
39    /// Calculate the number of leading zeros in the binary representation of this number.
40    #[must_use]
41    pub const fn leading_zeros(&self) -> u32 {
42        self.as_uint_ref().leading_zeros()
43    }
44
45    /// Get the precision of this [`BoxedUint`] in bits.
46    #[inline(always)]
47    #[must_use]
48    #[allow(clippy::cast_possible_truncation)]
49    pub fn bits_precision(&self) -> u32 {
50        self.limbs.len() as u32 * Limb::BITS
51    }
52
53    /// Calculate the number of trailing zeros in the binary representation of this number.
54    #[must_use]
55    pub fn trailing_zeros(&self) -> u32 {
56        self.as_uint_ref().trailing_zeros()
57    }
58
59    /// Calculate the number of trailing ones in the binary representation of this number.
60    #[must_use]
61    pub fn trailing_ones(&self) -> u32 {
62        self.as_uint_ref().trailing_ones()
63    }
64
65    /// Calculate the number of trailing zeros in the binary representation of this number in
66    /// variable-time with respect to `self`.
67    #[must_use]
68    pub fn trailing_zeros_vartime(&self) -> u32 {
69        self.as_uint_ref().trailing_zeros_vartime()
70    }
71
72    /// Calculate the number of trailing ones in the binary representation of this number,
73    /// variable time in `self`.
74    #[must_use]
75    pub fn trailing_ones_vartime(&self) -> u32 {
76        self.as_uint_ref().trailing_ones_vartime()
77    }
78
79    /// Sets the bit at `index` to 0 or 1 depending on the value of `bit_value`.
80    pub(crate) fn set_bit(&mut self, index: u32, bit_value: Choice) {
81        self.as_mut_uint_ref().set_bit(index, bit_value);
82    }
83
84    pub(crate) fn set_bit_vartime(&mut self, index: u32, bit_value: bool) {
85        self.as_mut_uint_ref().set_bit_vartime(index, bit_value);
86    }
87
88    /// Clear any bits at or above a given bit position.
89    pub(crate) const fn restrict_bits(&mut self, len: u32) {
90        self.as_mut_uint_ref().restrict_bits(len);
91    }
92}
93
94impl BitOps for BoxedUint {
95    fn bits_precision(&self) -> u32 {
96        self.bits_precision()
97    }
98
99    fn bytes_precision(&self) -> usize {
100        self.nlimbs() * Limb::BYTES
101    }
102
103    fn leading_zeros(&self) -> u32 {
104        self.leading_zeros()
105    }
106
107    fn bits(&self) -> u32 {
108        self.bits()
109    }
110
111    fn bit(&self, index: u32) -> Choice {
112        self.bit(index)
113    }
114
115    fn set_bit(&mut self, index: u32, bit_value: Choice) {
116        self.set_bit(index, bit_value);
117    }
118
119    fn trailing_zeros(&self) -> u32 {
120        self.trailing_zeros()
121    }
122
123    fn trailing_ones(&self) -> u32 {
124        self.trailing_ones()
125    }
126
127    fn bit_vartime(&self, index: u32) -> bool {
128        self.bit_vartime(index)
129    }
130
131    fn bits_vartime(&self) -> u32 {
132        self.bits_vartime()
133    }
134
135    fn set_bit_vartime(&mut self, index: u32, bit_value: bool) {
136        self.set_bit_vartime(index, bit_value);
137    }
138
139    fn trailing_zeros_vartime(&self) -> u32 {
140        self.trailing_zeros_vartime()
141    }
142
143    fn trailing_ones_vartime(&self) -> u32 {
144        self.trailing_ones_vartime()
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::BoxedUint;
151    use crate::Choice;
152    use hex_literal::hex;
153
154    fn uint_with_bits_at(positions: &[u32]) -> BoxedUint {
155        let mut result = BoxedUint::zero_with_precision(256);
156        for &pos in positions {
157            result |= BoxedUint::one_with_precision(256).shl_vartime(pos).unwrap();
158        }
159        result
160    }
161
162    #[test]
163    fn bit_vartime() {
164        let u = uint_with_bits_at(&[16, 48, 112, 127, 255]);
165        assert!(!u.bit_vartime(0));
166        assert!(!u.bit_vartime(1));
167        assert!(u.bit_vartime(16));
168        assert!(u.bit_vartime(127));
169        assert!(u.bit_vartime(255));
170        assert!(!u.bit_vartime(256));
171        assert!(!u.bit_vartime(260));
172    }
173
174    #[test]
175    fn bits() {
176        assert_eq!(0, BoxedUint::zero().bits());
177        assert_eq!(128, BoxedUint::max(128).bits());
178
179        let n1 = BoxedUint::from_be_slice(&hex!("000000000029ffffffffffffffffffff"), 128).unwrap();
180        assert_eq!(86, n1.bits());
181
182        let n2 = BoxedUint::from_be_slice(&hex!("00000000004000000000000000000000"), 128).unwrap();
183        assert_eq!(87, n2.bits());
184    }
185
186    #[test]
187    fn set_bit() {
188        let mut u = uint_with_bits_at(&[16, 79, 150]);
189        u.set_bit(127, Choice::TRUE);
190        assert_eq!(u, uint_with_bits_at(&[16, 79, 127, 150]));
191
192        let mut u = uint_with_bits_at(&[16, 79, 150]);
193        u.set_bit(150, Choice::TRUE);
194        assert_eq!(u, uint_with_bits_at(&[16, 79, 150]));
195
196        let mut u = uint_with_bits_at(&[16, 79, 150]);
197        u.set_bit(127, Choice::FALSE);
198        assert_eq!(u, uint_with_bits_at(&[16, 79, 150]));
199
200        let mut u = uint_with_bits_at(&[16, 79, 150]);
201        u.set_bit(150, Choice::FALSE);
202        assert_eq!(u, uint_with_bits_at(&[16, 79]));
203    }
204
205    #[test]
206    fn trailing_ones() {
207        let u = !uint_with_bits_at(&[16, 79, 150]);
208        assert_eq!(u.trailing_ones(), 16);
209
210        let u = !uint_with_bits_at(&[79, 150]);
211        assert_eq!(u.trailing_ones(), 79);
212
213        let u = !uint_with_bits_at(&[150, 207]);
214        assert_eq!(u.trailing_ones(), 150);
215
216        let u = !uint_with_bits_at(&[0, 150, 207]);
217        assert_eq!(u.trailing_ones(), 0);
218
219        let u = !BoxedUint::zero_with_precision(256);
220        assert_eq!(u.trailing_ones(), 256);
221    }
222
223    #[test]
224    fn trailing_ones_vartime() {
225        let u = !uint_with_bits_at(&[16, 79, 150]);
226        assert_eq!(u.trailing_ones_vartime(), 16);
227
228        let u = !uint_with_bits_at(&[79, 150]);
229        assert_eq!(u.trailing_ones_vartime(), 79);
230
231        let u = !uint_with_bits_at(&[150, 207]);
232        assert_eq!(u.trailing_ones_vartime(), 150);
233
234        let u = !uint_with_bits_at(&[0, 150, 207]);
235        assert_eq!(u.trailing_ones_vartime(), 0);
236
237        let u = !BoxedUint::zero_with_precision(256);
238        assert_eq!(u.trailing_ones_vartime(), 256);
239    }
240}