crypto_bigint/uint/boxed/
bits.rs1use 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 pub fn bit(&self, index: u32) -> Choice {
16 bit(&self.limbs, index).into()
17 }
18
19 #[inline(always)]
24 pub const fn bit_vartime(&self, index: u32) -> bool {
25 bit_vartime(&self.limbs, index)
26 }
27
28 pub fn bits(&self) -> u32 {
33 self.bits_precision() - self.leading_zeros()
34 }
35
36 pub fn bits_vartime(&self) -> u32 {
39 bits_vartime(&self.limbs)
40 }
41
42 pub const fn leading_zeros(&self) -> u32 {
44 leading_zeros(&self.limbs)
45 }
46
47 pub fn bits_precision(&self) -> u32 {
49 self.limbs.len() as u32 * Limb::BITS
50 }
51
52 pub fn trailing_zeros(&self) -> u32 {
54 trailing_zeros(&self.limbs)
55 }
56
57 pub fn trailing_ones(&self) -> u32 {
59 trailing_ones(&self.limbs)
60 }
61
62 pub fn trailing_zeros_vartime(&self) -> u32 {
65 trailing_zeros_vartime(&self.limbs)
66 }
67
68 pub fn trailing_ones_vartime(&self) -> u32 {
71 trailing_ones_vartime(&self.limbs)
72 }
73
74 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}