Skip to main content

crypto_bigint/uint/boxed/
bits.rs

1//! Bit manipulation functions.
2
3use crate::{BitOps, BoxedUint, Choice, Limb, bitlen};
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    pub fn bits_precision(&self) -> u32 {
49        bitlen::from_limbs(self.limbs.len())
50    }
51
52    /// Calculate the number of trailing zeros in the binary representation of this number.
53    #[must_use]
54    pub fn trailing_zeros(&self) -> u32 {
55        self.as_uint_ref().trailing_zeros()
56    }
57
58    /// Calculate the number of trailing ones in the binary representation of this number.
59    #[must_use]
60    pub fn trailing_ones(&self) -> u32 {
61        self.as_uint_ref().trailing_ones()
62    }
63
64    /// Calculate the number of trailing zeros in the binary representation of this number in
65    /// variable-time with respect to `self`.
66    #[must_use]
67    pub fn trailing_zeros_vartime(&self) -> u32 {
68        self.as_uint_ref().trailing_zeros_vartime()
69    }
70
71    /// Calculate the number of trailing ones in the binary representation of this number,
72    /// variable time in `self`.
73    #[must_use]
74    pub fn trailing_ones_vartime(&self) -> u32 {
75        self.as_uint_ref().trailing_ones_vartime()
76    }
77
78    /// Sets the bit at `index` to 0 or 1 depending on the value of `bit_value`.
79    pub(crate) fn set_bit(&mut self, index: u32, bit_value: Choice) {
80        self.as_mut_uint_ref().set_bit(index, bit_value);
81    }
82
83    pub(crate) fn set_bit_vartime(&mut self, index: u32, bit_value: bool) {
84        self.as_mut_uint_ref().set_bit_vartime(index, bit_value);
85    }
86
87    /// Clear any bits at or above a given bit position.
88    pub(crate) const fn restrict_bits(&mut self, len: u32) {
89        self.as_mut_uint_ref().restrict_bits(len);
90    }
91}
92
93impl BitOps for BoxedUint {
94    fn bits_precision(&self) -> u32 {
95        self.bits_precision()
96    }
97
98    fn bytes_precision(&self) -> usize {
99        self.nlimbs() * Limb::BYTES
100    }
101
102    fn leading_zeros(&self) -> u32 {
103        self.leading_zeros()
104    }
105
106    fn bits(&self) -> u32 {
107        self.bits()
108    }
109
110    fn bit(&self, index: u32) -> Choice {
111        self.bit(index)
112    }
113
114    fn set_bit(&mut self, index: u32, bit_value: Choice) {
115        self.set_bit(index, bit_value);
116    }
117
118    fn trailing_zeros(&self) -> u32 {
119        self.trailing_zeros()
120    }
121
122    fn trailing_ones(&self) -> u32 {
123        self.trailing_ones()
124    }
125
126    fn bit_vartime(&self, index: u32) -> bool {
127        self.bit_vartime(index)
128    }
129
130    fn bits_vartime(&self) -> u32 {
131        self.bits_vartime()
132    }
133
134    fn set_bit_vartime(&mut self, index: u32, bit_value: bool) {
135        self.set_bit_vartime(index, bit_value);
136    }
137
138    fn trailing_zeros_vartime(&self) -> u32 {
139        self.trailing_zeros_vartime()
140    }
141
142    fn trailing_ones_vartime(&self) -> u32 {
143        self.trailing_ones_vartime()
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::BoxedUint;
150    use crate::Choice;
151    use hex_literal::hex;
152
153    fn uint_with_bits_at(positions: &[u32]) -> BoxedUint {
154        let mut result = BoxedUint::zero_with_precision(256);
155        for &pos in positions {
156            result |= BoxedUint::one_with_precision(256).shl_vartime(pos).unwrap();
157        }
158        result
159    }
160
161    #[test]
162    fn bit_vartime() {
163        let u = uint_with_bits_at(&[16, 48, 112, 127, 255]);
164        assert!(!u.bit_vartime(0));
165        assert!(!u.bit_vartime(1));
166        assert!(u.bit_vartime(16));
167        assert!(u.bit_vartime(127));
168        assert!(u.bit_vartime(255));
169        assert!(!u.bit_vartime(256));
170        assert!(!u.bit_vartime(260));
171    }
172
173    #[test]
174    fn bits() {
175        assert_eq!(0, BoxedUint::zero().bits());
176        assert_eq!(128, BoxedUint::max(128).bits());
177
178        let n1 = BoxedUint::from_be_slice(&hex!("000000000029ffffffffffffffffffff"), 128).unwrap();
179        assert_eq!(86, n1.bits());
180
181        let n2 = BoxedUint::from_be_slice(&hex!("00000000004000000000000000000000"), 128).unwrap();
182        assert_eq!(87, n2.bits());
183    }
184
185    #[test]
186    fn set_bit() {
187        let mut u = uint_with_bits_at(&[16, 79, 150]);
188        u.set_bit(127, Choice::TRUE);
189        assert_eq!(u, uint_with_bits_at(&[16, 79, 127, 150]));
190
191        let mut u = uint_with_bits_at(&[16, 79, 150]);
192        u.set_bit(150, Choice::TRUE);
193        assert_eq!(u, uint_with_bits_at(&[16, 79, 150]));
194
195        let mut u = uint_with_bits_at(&[16, 79, 150]);
196        u.set_bit(127, Choice::FALSE);
197        assert_eq!(u, uint_with_bits_at(&[16, 79, 150]));
198
199        let mut u = uint_with_bits_at(&[16, 79, 150]);
200        u.set_bit(150, Choice::FALSE);
201        assert_eq!(u, uint_with_bits_at(&[16, 79]));
202    }
203
204    #[test]
205    fn trailing_ones() {
206        let u = !uint_with_bits_at(&[16, 79, 150]);
207        assert_eq!(u.trailing_ones(), 16);
208
209        let u = !uint_with_bits_at(&[79, 150]);
210        assert_eq!(u.trailing_ones(), 79);
211
212        let u = !uint_with_bits_at(&[150, 207]);
213        assert_eq!(u.trailing_ones(), 150);
214
215        let u = !uint_with_bits_at(&[0, 150, 207]);
216        assert_eq!(u.trailing_ones(), 0);
217
218        let u = !BoxedUint::zero_with_precision(256);
219        assert_eq!(u.trailing_ones(), 256);
220    }
221
222    #[test]
223    fn trailing_ones_vartime() {
224        let u = !uint_with_bits_at(&[16, 79, 150]);
225        assert_eq!(u.trailing_ones_vartime(), 16);
226
227        let u = !uint_with_bits_at(&[79, 150]);
228        assert_eq!(u.trailing_ones_vartime(), 79);
229
230        let u = !uint_with_bits_at(&[150, 207]);
231        assert_eq!(u.trailing_ones_vartime(), 150);
232
233        let u = !uint_with_bits_at(&[0, 150, 207]);
234        assert_eq!(u.trailing_ones_vartime(), 0);
235
236        let u = !BoxedUint::zero_with_precision(256);
237        assert_eq!(u.trailing_ones_vartime(), 256);
238    }
239}