1use cfx_types::U256;
2use std::ops::{Shl, Shr};
3use typenum::Unsigned;
4
5use super::{nth_root, NthRoot, RootDegree, RootInvParams};
6
7pub fn nth_inv_root<N: RootDegree, P: Unsigned>(input: U256) -> U256
8where (N, P): RootInvParams {
9 if input.is_zero() {
10 return U256::MAX;
11 }
12 let min_bits = N::USIZE * P::USIZE + 1;
13
14 let bits = input.bits();
15 let ideal_bits = min_bits + (bits - 1) % N::USIZE;
16
17 let adjusted_input =
18 rotate_right(input, bits as isize - ideal_bits as isize);
19 let back_rotate = (bits as isize - ideal_bits as isize) / N::ISIZE;
20
21 let root = nth_root::<N, _>(adjusted_input);
22 let root_bits = root.bits();
23
24 if root_bits + P::USIZE <= 64 {
25 rotate_right(U256::from(u64::MAX / root.low_u64()), back_rotate - 192)
26 } else if root_bits + P::USIZE <= 128 {
27 rotate_right(U256::from(u128::MAX / root.low_u128()), back_rotate - 128)
28 } else {
29 rotate_right(U256::MAX / root, back_rotate)
30 }
31}
32
33#[inline]
34fn rotate_right<I: Shr<usize, Output = I> + Shl<usize, Output = I>>(
35 input: I, bits: isize,
36) -> I {
37 if bits >= 0 {
38 input >> bits as usize
39 } else {
40 input << (-bits) as usize
41 }
42}