@@ -30,19 +30,139 @@ impl<const LIMBS: usize> Uint<LIMBS> {
3030 )
3131 . 0 as usize
3232 }
33+
34+ /// Calculate the number of leading zeros in the binary representation of this number.
35+ pub const fn leading_zeros ( self ) -> usize {
36+ let limbs = self . as_limbs ( ) ;
37+
38+ let mut count: Word = 0 ;
39+ let mut i = LIMBS ;
40+ let mut mask = Word :: MAX ;
41+ while i > 0 {
42+ i -= 1 ;
43+ let l = limbs[ i] ;
44+ let z = l. leading_zeros ( ) as Word ;
45+ count += z & mask;
46+ mask &= !l. is_nonzero ( ) ;
47+ }
48+
49+ count as usize
50+ }
51+
52+ /// Calculate the number of trailing zeros in the binary representation of this number.
53+ pub const fn trailing_zeros ( self ) -> usize {
54+ let limbs = self . as_limbs ( ) ;
55+
56+ let mut count: Word = 0 ;
57+ let mut i = 0 ;
58+ let mut mask = Word :: MAX ;
59+ while i < LIMBS {
60+ let l = limbs[ i] ;
61+ let z = l. trailing_zeros ( ) as Word ;
62+ count += z & mask;
63+ mask &= !l. is_nonzero ( ) ;
64+ i += 1 ;
65+ }
66+
67+ count as usize
68+ }
69+
70+ /// Calculate the number of bits needed to represent this number.
71+ pub const fn bits ( self ) -> usize {
72+ LIMBS * Limb :: BIT_SIZE - self . leading_zeros ( )
73+ }
74+
75+ /// Get the value of the bit at position `index`, as a 0- or 1-valued Word.
76+ /// Returns 0 for indices out of range.
77+ pub const fn bit ( self , index : usize ) -> Word {
78+ let limb_num = Limb ( ( index / Limb :: BIT_SIZE ) as Word ) ;
79+ let index_in_limb = index % Limb :: BIT_SIZE ;
80+ let index_mask = 1 << index_in_limb;
81+
82+ let limbs = self . as_words ( ) ;
83+
84+ let mut result: Word = 0 ;
85+ let mut i = 0 ;
86+ while i < LIMBS {
87+ let bit = limbs[ i] & index_mask;
88+ let is_right_limb = Limb :: ct_eq ( limb_num, Limb ( i as Word ) ) ;
89+ result |= bit & is_right_limb;
90+ i += 1 ;
91+ }
92+
93+ result >> index_in_limb
94+ }
3395}
3496
3597#[ cfg( test) ]
3698mod tests {
37- use crate :: U128 ;
99+ use crate :: U256 ;
100+
101+ fn uint_with_bits_at ( positions : & [ usize ] ) -> U256 {
102+ let mut result = U256 :: ZERO ;
103+ for pos in positions {
104+ result |= U256 :: ONE << * pos;
105+ }
106+ result
107+ }
38108
39109 #[ test]
40- fn bit_vartime_ok ( ) {
41- let u = U128 :: from_be_hex ( "f0010000000000000001000000010000" ) ;
110+ fn bit_vartime ( ) {
111+ let u = uint_with_bits_at ( & [ 16 , 48 , 112 , 127 , 255 ] ) ;
42112 assert_eq ! ( u. bit_vartime( 0 ) , 0 ) ;
43113 assert_eq ! ( u. bit_vartime( 1 ) , 0 ) ;
44114 assert_eq ! ( u. bit_vartime( 16 ) , 1 ) ;
45115 assert_eq ! ( u. bit_vartime( 127 ) , 1 ) ;
46- assert_eq ! ( u. bit_vartime( 130 ) , 0 ) ;
116+ assert_eq ! ( u. bit_vartime( 255 ) , 1 ) ;
117+ assert_eq ! ( u. bit_vartime( 256 ) , 0 ) ;
118+ assert_eq ! ( u. bit_vartime( 260 ) , 0 ) ;
119+ }
120+
121+ #[ test]
122+ fn bit ( ) {
123+ let u = uint_with_bits_at ( & [ 16 , 48 , 112 , 127 , 255 ] ) ;
124+ assert_eq ! ( u. bit( 0 ) , 0 ) ;
125+ assert_eq ! ( u. bit( 1 ) , 0 ) ;
126+ assert_eq ! ( u. bit( 16 ) , 1 ) ;
127+ assert_eq ! ( u. bit( 127 ) , 1 ) ;
128+ assert_eq ! ( u. bit( 255 ) , 1 ) ;
129+ assert_eq ! ( u. bit( 256 ) , 0 ) ;
130+ assert_eq ! ( u. bit( 260 ) , 0 ) ;
131+ }
132+
133+ #[ test]
134+ fn leading_zeros ( ) {
135+ let u = uint_with_bits_at ( & [ 256 - 16 , 256 - 79 , 256 - 207 ] ) ;
136+ assert_eq ! ( u. leading_zeros( ) as u32 , 15 ) ;
137+
138+ let u = uint_with_bits_at ( & [ 256 - 79 , 256 - 207 ] ) ;
139+ assert_eq ! ( u. leading_zeros( ) as u32 , 78 ) ;
140+
141+ let u = uint_with_bits_at ( & [ 256 - 207 ] ) ;
142+ assert_eq ! ( u. leading_zeros( ) as u32 , 206 ) ;
143+
144+ let u = uint_with_bits_at ( & [ 256 - 1 , 256 - 75 , 256 - 150 ] ) ;
145+ assert_eq ! ( u. leading_zeros( ) as u32 , 0 ) ;
146+
147+ let u = U256 :: ZERO ;
148+ assert_eq ! ( u. leading_zeros( ) as u32 , 256 ) ;
149+ }
150+
151+ #[ test]
152+ fn trailing_zeros ( ) {
153+ let u = uint_with_bits_at ( & [ 16 , 79 , 150 ] ) ;
154+ assert_eq ! ( u. trailing_zeros( ) as u32 , 16 ) ;
155+
156+ let u = uint_with_bits_at ( & [ 79 , 150 ] ) ;
157+ assert_eq ! ( u. trailing_zeros( ) as u32 , 79 ) ;
158+
159+ let u = uint_with_bits_at ( & [ 150 , 207 ] ) ;
160+ assert_eq ! ( u. trailing_zeros( ) as u32 , 150 ) ;
161+
162+ let u = uint_with_bits_at ( & [ 0 , 150 , 207 ] ) ;
163+ assert_eq ! ( u. trailing_zeros( ) as u32 , 0 ) ;
164+
165+ let u = U256 :: ZERO ;
166+ assert_eq ! ( u. trailing_zeros( ) as u32 , 256 ) ;
47167 }
48168}
0 commit comments