crypto_bigint/uint/ref_type/
bits.rs1use super::UintRef;
2use crate::{Choice, Limb, traits::BitOps, word};
3
4impl UintRef {
5 #[allow(clippy::cast_possible_truncation)]
7 #[must_use]
8 pub const fn bits_precision(&self) -> u32 {
9 self.limbs.len() as u32 * Limb::BITS
10 }
11
12 #[inline(always)]
15 #[allow(clippy::cast_possible_truncation)]
16 #[must_use]
17 pub const fn bit(&self, index: u32) -> Choice {
18 let limb_num = index >> Limb::LOG2_BITS;
19 let index_in_limb = index & (Limb::BITS - 1);
20 let index_mask = 1 << index_in_limb;
21
22 let mut result = 0;
23 let mut i = 0;
24 while i < self.limbs.len() {
25 let is_right_limb = Choice::from_u32_eq(i as u32, limb_num);
26 result |= word::select(0, self.limbs[i].0, is_right_limb);
27 i += 1;
28 }
29
30 word::choice_from_lsb((result & index_mask) >> index_in_limb)
31 }
32
33 #[inline(always)]
39 #[must_use]
40 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
41 pub const fn bit_vartime(&self, index: u32) -> bool {
42 let limb_num = (index / Limb::BITS) as usize;
43 let index_in_limb = index % Limb::BITS;
44 if limb_num >= self.limbs.len() {
45 false
46 } else {
47 (self.limbs[limb_num].0 >> index_in_limb) & 1 == 1
48 }
49 }
50
51 #[inline(always)]
56 #[must_use]
57 pub const fn bits(&self) -> u32 {
58 self.bits_precision() - self.leading_zeros()
59 }
60
61 #[inline(always)]
64 #[allow(clippy::cast_possible_truncation)]
65 #[must_use]
66 pub const fn bits_vartime(&self) -> u32 {
67 let mut i = self.limbs.len() - 1;
68 while i > 0 && self.limbs[i].0 == 0 {
69 i -= 1;
70 }
71
72 let limb = self.limbs[i];
73 Limb::BITS * (i as u32 + 1) - limb.leading_zeros()
74 }
75
76 #[inline(always)]
78 #[allow(clippy::cast_possible_truncation)]
79 pub const fn set_bit(&mut self, index: u32, bit_value: Choice) {
80 let limb_num = index >> Limb::LOG2_BITS;
81 let index_in_limb = index & (Limb::BITS - 1);
82 let index_mask = 1 << index_in_limb;
83
84 let mut i = 0;
85 while i < self.limbs.len() {
86 let is_right_limb = Choice::from_u32_eq(i as u32, limb_num);
87 let old_limb = self.limbs[i].0;
88 let new_limb = word::select(old_limb & !index_mask, old_limb | index_mask, bit_value);
89 self.limbs[i] = Limb(word::select(old_limb, new_limb, is_right_limb));
90 i += 1;
91 }
92 }
93
94 #[inline(always)]
97 #[track_caller]
98 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
99 pub const fn set_bit_vartime(&mut self, index: u32, bit_value: bool) {
100 let limb_num = (index / Limb::BITS) as usize;
101 let index_in_limb = index % Limb::BITS;
102 if bit_value {
103 self.limbs[limb_num].0 |= 1 << index_in_limb;
104 } else {
105 self.limbs[limb_num].0 &= !(1 << index_in_limb);
106 }
107 }
108
109 #[must_use]
111 pub const fn leading_zeros(&self) -> u32 {
112 let mut count = 0;
113 let mut i = self.limbs.len();
114 let mut nonzero_limb_not_encountered = Choice::TRUE;
115 while i > 0 {
116 i -= 1;
117 let l = self.limbs[i];
118 let z = l.leading_zeros();
119 count += nonzero_limb_not_encountered.select_u32(0, z);
120 nonzero_limb_not_encountered =
121 nonzero_limb_not_encountered.and(word::choice_from_nz(l.0).not());
122 }
123
124 count
125 }
126
127 #[inline(always)]
129 #[must_use]
130 pub const fn trailing_zeros(&self) -> u32 {
131 let mut count = 0;
132 let mut i = 0;
133 let mut nonzero_limb_not_encountered = Choice::TRUE;
134 while i < self.limbs.len() {
135 let l = self.limbs[i];
136 let z = l.trailing_zeros();
137 count += nonzero_limb_not_encountered.select_u32(0, z);
138 nonzero_limb_not_encountered =
139 nonzero_limb_not_encountered.and(word::choice_from_nz(l.0).not());
140 i += 1;
141 }
142
143 count
144 }
145
146 #[inline(always)]
149 #[must_use]
150 pub const fn trailing_zeros_vartime(&self) -> u32 {
151 let mut count = 0;
152 let mut i = 0;
153 while i < self.limbs.len() {
154 let l = self.limbs[i];
155 let z = l.trailing_zeros();
156 count += z;
157 if z != Limb::BITS {
158 break;
159 }
160 i += 1;
161 }
162
163 count
164 }
165
166 #[inline(always)]
168 #[must_use]
169 pub const fn trailing_ones(&self) -> u32 {
170 let mut count = 0;
171 let mut i = 0;
172 let mut nonmax_limb_not_encountered = Choice::TRUE;
173 while i < self.limbs.len() {
174 let l = self.limbs[i];
175 let z = l.trailing_ones();
176 count += nonmax_limb_not_encountered.select_u32(0, z);
177 nonmax_limb_not_encountered =
178 nonmax_limb_not_encountered.and(word::choice_from_eq(l.0, Limb::MAX.0));
179 i += 1;
180 }
181
182 count
183 }
184
185 #[inline(always)]
188 #[must_use]
189 pub const fn trailing_ones_vartime(&self) -> u32 {
190 let mut count = 0;
191 let mut i = 0;
192 while i < self.limbs.len() {
193 let l = self.limbs[i];
194 let z = l.trailing_ones();
195 count += z;
196 if z != Limb::BITS {
197 break;
198 }
199 i += 1;
200 }
201
202 count
203 }
204
205 #[allow(clippy::cast_possible_truncation)]
207 pub const fn restrict_bits(&mut self, len: u32) {
208 let limb = len >> Limb::LOG2_BITS;
209 let limb_mask = Limb((1 << (len & (Limb::BITS - 1))) - 1);
210 let mut i = 0;
211 let mut clear = Choice::FALSE;
212 while i < self.nlimbs() {
213 let apply = Choice::from_u32_eq(i as u32, limb);
214 self.limbs[i] = self.limbs[i].bitand(Limb::select(
215 Limb(word::choice_to_mask(clear.not())),
216 limb_mask,
217 apply,
218 ));
219 clear = clear.or(apply);
220 i += 1;
221 }
222 }
223}
224
225impl BitOps for UintRef {
226 #[inline(always)]
227 fn bits_precision(&self) -> u32 {
228 self.bits_precision()
229 }
230
231 #[inline(always)]
232 fn bytes_precision(&self) -> usize {
233 self.limbs.len()
234 }
235
236 fn leading_zeros(&self) -> u32 {
237 self.leading_zeros()
238 }
239
240 fn bit(&self, index: u32) -> Choice {
241 self.bit(index)
242 }
243
244 fn set_bit(&mut self, index: u32, bit_value: Choice) {
245 self.set_bit(index, bit_value);
246 }
247
248 fn trailing_zeros(&self) -> u32 {
249 self.trailing_zeros()
250 }
251
252 fn trailing_ones(&self) -> u32 {
253 self.trailing_ones()
254 }
255
256 fn bit_vartime(&self, index: u32) -> bool {
257 self.bit_vartime(index)
258 }
259
260 fn bits_vartime(&self) -> u32 {
261 self.bits_vartime()
262 }
263
264 fn set_bit_vartime(&mut self, index: u32, bit_value: bool) {
265 self.set_bit_vartime(index, bit_value);
266 }
267
268 fn trailing_zeros_vartime(&self) -> u32 {
269 self.trailing_zeros_vartime()
270 }
271
272 fn trailing_ones_vartime(&self) -> u32 {
273 self.trailing_ones_vartime()
274 }
275}