1use super::cmp::ct_select;
17use super::shift::ct_shl;
18use super::{HeaplessBigInt, arith::max_at_len};
19use crate::MachineWord;
20use const_num_traits::{
21 Ct, IsPowerOfTwo, Nct, NextPowerOfTwo, One, Personality, PersonalityTag, PrimBits, WrappingSub,
22 Zero,
23};
24
25impl<T, const CAP: usize, P: Personality> IsPowerOfTwo for HeaplessBigInt<T, CAP, P>
26where
27 T: MachineWord,
28{
29 fn is_power_of_two(self) -> bool {
30 match P::TAG {
32 PersonalityTag::Nct => {
33 !<Self as Zero>::is_zero(&self)
34 && <Self as Zero>::is_zero(&(self & (self - <Self as One>::one())))
35 }
36 PersonalityTag::Ct => {
37 let a = core::hint::black_box(!<Self as Zero>::is_zero(&self));
40 let b = <Self as Zero>::is_zero(
41 &(self & <Self as WrappingSub>::wrapping_sub(self, Self::one())),
42 );
43 a & b
44 }
45 }
46 }
47}
48
49impl<T, const CAP: usize, P: Personality> HeaplessBigInt<T, CAP, P>
54where
55 T: MachineWord,
56{
57 fn checked_next_pow2(self) -> Option<Self> {
58 let width = self.len();
59 let word_bits = core::mem::size_of::<T>() as u32 * 8;
60 let width_bits = width as u32 * word_bits;
61 if <Self as Zero>::is_zero(&self) {
62 return Some(<Self as One>::one().widened(core::cmp::max(1, width)));
63 }
64 let m_one = <Self as WrappingSub>::wrapping_sub(self, <Self as One>::one());
66 let bits = width_bits - PrimBits::leading_zeros(m_one);
67 if bits >= width_bits {
68 return None; }
70 Some(<Self as One>::one().widened(core::cmp::max(1, width)) << (bits as usize))
71 }
72}
73
74impl<T, const CAP: usize> NextPowerOfTwo for HeaplessBigInt<T, CAP, Nct>
75where
76 T: MachineWord,
77{
78 type Output = Self;
79
80 fn wrapping_next_power_of_two(self) -> Self {
81 let width = self.len();
82 self.checked_next_pow2()
83 .unwrap_or_else(|| Self::new_zero_with_len(width))
84 }
85
86 fn next_power_of_two(self) -> Self {
87 self.checked_next_pow2().unwrap_or_else(|| {
88 panic!("HeaplessBigInt::next_power_of_two overflow: exceeds the value width")
89 })
90 }
91
92 fn checked_next_power_of_two(self) -> Option<Self> {
93 self.checked_next_pow2()
94 }
95}
96
97#[inline]
104fn ct_next_pow2<T, const CAP: usize>(
105 x: HeaplessBigInt<T, CAP, Ct>,
106 overflow_sentinel: HeaplessBigInt<T, CAP, Ct>,
107) -> HeaplessBigInt<T, CAP, Ct>
108where
109 T: MachineWord + subtle::ConditionallySelectable,
110{
111 type H<T, const CAP: usize> = HeaplessBigInt<T, CAP, Ct>;
112 let width = x.len();
113 let word_bits = core::mem::size_of::<T>() as u32 * 8;
114 let width_bits = width as u32 * word_bits;
115 let one_w = <H<T, CAP> as One>::one().widened(core::cmp::max(1, width));
116 let m_one = <H<T, CAP> as WrappingSub>::wrapping_sub(x, one_w);
117 let bits = width_bits - PrimBits::leading_zeros(m_one);
118 let shifted = ct_shl(one_w, bits); let is_zero = <H<T, CAP> as Zero>::is_zero(&x);
120 let overflow = (bits >= width_bits) & !is_zero;
121 let saturated = ct_select(&shifted, &overflow_sentinel, overflow);
122 ct_select(&saturated, &one_w, is_zero)
123}
124
125impl<T, const CAP: usize> NextPowerOfTwo for HeaplessBigInt<T, CAP, Ct>
126where
127 T: MachineWord + subtle::ConditionallySelectable,
128{
129 type Output = Self;
130
131 fn next_power_of_two(self) -> Self {
132 ct_next_pow2(self, max_at_len(self.len()))
135 }
136
137 fn wrapping_next_power_of_two(self) -> Self {
138 ct_next_pow2(self, Self::new_zero_with_len(self.len()))
139 }
140
141 fn checked_next_power_of_two(self) -> Option<Self> {
142 self.checked_next_pow2()
144 }
145}
146
147impl<T, const CAP: usize, P: Personality> IsPowerOfTwo for &HeaplessBigInt<T, CAP, P>
149where
150 T: MachineWord,
151{
152 fn is_power_of_two(self) -> bool {
153 <HeaplessBigInt<T, CAP, P> as IsPowerOfTwo>::is_power_of_two(*self)
154 }
155}
156
157impl<T, const CAP: usize> NextPowerOfTwo for &HeaplessBigInt<T, CAP, Nct>
158where
159 T: MachineWord,
160{
161 type Output = HeaplessBigInt<T, CAP, Nct>;
162
163 fn wrapping_next_power_of_two(self) -> Self::Output {
164 <HeaplessBigInt<T, CAP, Nct> as NextPowerOfTwo>::wrapping_next_power_of_two(*self)
165 }
166
167 fn next_power_of_two(self) -> Self::Output {
168 <HeaplessBigInt<T, CAP, Nct> as NextPowerOfTwo>::next_power_of_two(*self)
169 }
170
171 fn checked_next_power_of_two(self) -> Option<Self::Output> {
172 <HeaplessBigInt<T, CAP, Nct> as NextPowerOfTwo>::checked_next_power_of_two(*self)
173 }
174}
175
176impl<T, const CAP: usize> NextPowerOfTwo for &HeaplessBigInt<T, CAP, Ct>
177where
178 T: MachineWord + subtle::ConditionallySelectable,
179{
180 type Output = HeaplessBigInt<T, CAP, Ct>;
181
182 fn next_power_of_two(self) -> Self::Output {
183 <HeaplessBigInt<T, CAP, Ct> as NextPowerOfTwo>::next_power_of_two(*self)
184 }
185
186 fn wrapping_next_power_of_two(self) -> Self::Output {
187 <HeaplessBigInt<T, CAP, Ct> as NextPowerOfTwo>::wrapping_next_power_of_two(*self)
188 }
189
190 fn checked_next_power_of_two(self) -> Option<Self::Output> {
191 <HeaplessBigInt<T, CAP, Ct> as NextPowerOfTwo>::checked_next_power_of_two(*self)
192 }
193}
194
195impl<T, const CAP: usize, P: Personality> const_num_traits::ops::ct::CtIsPowerOfTwo
199 for HeaplessBigInt<T, CAP, P>
200where
201 T: MachineWord + subtle::ConstantTimeEq,
202{
203 fn ct_is_power_of_two(&self) -> subtle::Choice {
204 use const_num_traits::ops::ct::CtIsZero;
205 let nonzero = !self.ct_is_zero();
206 let one = <Self as const_num_traits::ConstOne>::ONE;
207 let masked = *self & <Self as WrappingSub>::wrapping_sub(*self, one);
208 nonzero & masked.ct_is_zero()
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::HeaplessBigInt;
215 use const_num_traits::NextPowerOfTwo;
216 use const_num_traits::ops::ct::CtIsPowerOfTwo;
217
218 type H = HeaplessBigInt<u8, 8>;
219
220 #[test]
224 fn next_power_of_two_preserves_width() {
225 let five = H::from(5u8).widened(8);
226 let np = NextPowerOfTwo::next_power_of_two(five);
227 assert_eq!(np, H::from(8u8));
228 assert_eq!(np.len(), 8);
229
230 let zero = H::new_zero_with_len(8);
232 let np0 = NextPowerOfTwo::next_power_of_two(zero);
233 assert_eq!(np0, H::from(1u8));
234 assert_eq!(np0.len(), 8);
235
236 let already = H::from(128u8).widened(8);
237 let np2 = NextPowerOfTwo::next_power_of_two(already);
238 assert_eq!(np2.len(), 8);
239 }
240
241 #[test]
242 fn checked_overflow_at_value_width() {
243 let x = HeaplessBigInt::<u8, 8>::from(0x81u8);
245 assert_eq!(x.len(), 1);
246 assert_eq!(NextPowerOfTwo::checked_next_power_of_two(x), None);
247 let w = NextPowerOfTwo::wrapping_next_power_of_two(x);
249 assert_eq!(w, HeaplessBigInt::<u8, 8>::from(0u8));
250 assert_eq!(w.len(), 1);
251 }
252
253 #[test]
254 fn ct_is_power_of_two_matches_bool() {
255 for v in [0u32, 1, 2, 3, 4, 100, 255, 256, 0x8000_0000] {
256 let h = H::from(v);
257 let ct = bool::from(h.ct_is_power_of_two());
258 assert_eq!(ct, v != 0 && v & (v - 1) == 0, "ct_is_power_of_two({v})");
259 }
260 }
261
262 #[test]
263 fn ct_next_power_of_two_matches_and_saturates() {
264 use const_num_traits::Ct;
265 type HC = HeaplessBigInt<u8, 4, Ct>;
266
267 for v in [1u32, 5, 128, 0x4000_0000] {
269 assert_eq!(
270 NextPowerOfTwo::next_power_of_two(HC::from(v)),
271 HC::from(v.next_power_of_two()),
272 "ct next_power_of_two({v})"
273 );
274 }
275 assert_eq!(
277 NextPowerOfTwo::next_power_of_two(HC::from(0u8).widened(4)),
278 HC::from(1u8)
279 );
280 let big = HC::from(0x8000_0001u32);
283 assert_eq!(
284 NextPowerOfTwo::next_power_of_two(big),
285 HC::from(0xFFFF_FFFFu32)
286 );
287 assert_eq!(
288 NextPowerOfTwo::wrapping_next_power_of_two(big),
289 HC::from(0u8)
290 );
291 assert_eq!(NextPowerOfTwo::checked_next_power_of_two(big), None);
292 }
293
294 #[test]
295 fn byref_matches_value() {
296 use const_num_traits::{Ct, IsPowerOfTwo};
297 let a = H::from(5u8);
298 let r = &a; assert_eq!(
300 IsPowerOfTwo::is_power_of_two(r),
301 IsPowerOfTwo::is_power_of_two(a)
302 );
303 assert_eq!(
304 NextPowerOfTwo::next_power_of_two(r),
305 NextPowerOfTwo::next_power_of_two(a)
306 );
307 assert_eq!(
308 NextPowerOfTwo::wrapping_next_power_of_two(r),
309 NextPowerOfTwo::wrapping_next_power_of_two(a)
310 );
311 assert_eq!(
312 NextPowerOfTwo::checked_next_power_of_two(r),
313 NextPowerOfTwo::checked_next_power_of_two(a)
314 );
315
316 type HC = HeaplessBigInt<u8, 4, Ct>;
317 let c = HC::from(5u8);
318 assert_eq!(
319 NextPowerOfTwo::next_power_of_two(&c),
320 NextPowerOfTwo::next_power_of_two(c)
321 );
322 }
323}