crypto_bigint/uint/boxed/
bits.rs

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