@@ -190,9 +190,9 @@ static size_t count16(const uint16_t *num, size_t num_len)
190
190
return count ;
191
191
}
192
192
193
- static inline uint32_t nlz (uint32_t x )
193
+ // make sure that x != 0 before calling this function
194
+ static inline uint32_t uint32_nlz (uint32_t x )
194
195
{
195
- // This function is used only from divmnu, that doesn't allow 32 leading zeros
196
196
ASSUME (x != 0 );
197
197
198
198
#ifdef __has_builtin
@@ -272,7 +272,7 @@ static int divmnu16(
272
272
// same amount. We may have to append a high-order
273
273
// digit on the dividend; we do that unconditionally.
274
274
275
- s = nlz (v [n - 1 ]) - 16 ; // 0 <= s <= 15.
275
+ s = uint32_nlz (v [n - 1 ]) - 16 ; // 0 <= s <= 15.
276
276
uint16_t vn [INTN_DIVMNU_MAX_IN_LEN * (sizeof (intn_digit_t ) / sizeof (uint16_t ))];
277
277
for (i = n - 1 ; i > 0 ; i -- )
278
278
vn [i ] = (v [i ] << s ) | (v [i - 1 ] >> (16 - s ));
@@ -694,3 +694,97 @@ int intn_from_integer_bytes(const uint8_t in[], size_t in_size, intn_from_intege
694
694
695
695
return cond_neg_in_place (sign , out );
696
696
}
697
+
698
+ int intn_to_integer_bytes (const intn_digit_t in [], size_t in_len , intn_integer_sign_t in_sign ,
699
+ intn_from_integer_options_t opts , uint8_t out [], size_t out_len )
700
+ {
701
+ size_t count = intn_count_digits (in , in_len );
702
+ if (UNLIKELY (count == 0 )) {
703
+ memset (out , 0 , out_len );
704
+ return out_len ;
705
+ }
706
+
707
+ size_t to_copy = (count - 1 );
708
+ size_t to_copy_bytes = to_copy * sizeof (intn_digit_t );
709
+
710
+ if (UNLIKELY (to_copy_bytes > out_len )) {
711
+ return -1 ;
712
+ }
713
+
714
+ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
715
+ memcpy (out , in , to_copy_bytes );
716
+ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
717
+ for (size_t i = 0 ; i < to_copy ; i ++ ) {
718
+ out [i * 4 ] = in [i ] & 0xFF ;
719
+ out [i * 4 + 1 ] = (in [i ] >> 8 ) & 0xFF ;
720
+ out [i * 4 + 2 ] = (in [i ] >> 16 ) & 0xFF ;
721
+ out [i * 4 + 3 ] = (in [i ] >> 24 ) & 0xFF ;
722
+ }
723
+ #else
724
+ #error "Unsupported endianess"
725
+ #endif
726
+
727
+ intn_digit_t last_in = in [to_copy ];
728
+ size_t k ;
729
+ for (k = to_copy * 4 ; k < (to_copy + 1 ) * 4 ; k ++ ) {
730
+ if (last_in == 0 ) {
731
+ break ;
732
+ }
733
+ if (UNLIKELY (k >= out_len )) {
734
+ return -1 ;
735
+ }
736
+ out [k ] = last_in & 0xFF ;
737
+ last_in >>= 8 ;
738
+ }
739
+ size_t copied_len = k ;
740
+
741
+ bool negate = false;
742
+ if ((opts & IntnSigned ) && (in_sign == IntNNegativeInteger )) {
743
+ negate = true;
744
+ }
745
+
746
+ uint8_t filler = 0x00 ;
747
+ if (negate ) {
748
+ filler = 0xFF ;
749
+ unsigned int carry = 1 ;
750
+ for (size_t i = 0 ; i < copied_len ; i ++ ) {
751
+ unsigned int temp = ((int ) (~out [i ])) + carry ;
752
+ out [i ] = temp & 0xFF ;
753
+ carry = temp >> 8 ;
754
+ }
755
+ }
756
+
757
+ if ((opts & IntnSigned ) && (copied_len == out_len )) {
758
+ uint8_t last_byte = out [copied_len - 1 ];
759
+ if (UNLIKELY (
760
+ (negate && ((last_byte & 0x80 ) == 0 )) || (!negate && ((last_byte & 0x80 ) != 0 )))) {
761
+ return -1 ;
762
+ }
763
+ }
764
+
765
+ memset (out + copied_len , filler , out_len - copied_len );
766
+
767
+ // rotate when big endian
768
+ if (!(opts & IntnLittleEndian )) {
769
+ for (size_t i = 0 ; i < out_len / 2 ; i ++ ) {
770
+ uint8_t tmp = out [i ];
771
+ out [i ] = out [out_len - 1 - i ];
772
+ out [out_len - 1 - i ] = tmp ;
773
+ }
774
+ }
775
+
776
+ return out_len ;
777
+ }
778
+
779
+ size_t intn_required_unsigned_integer_bytes (const intn_digit_t in [], size_t in_len )
780
+ {
781
+ int i ;
782
+ for (i = in_len - 1 ; i >= 0 ; i -- ) {
783
+ uint32_t in_i = in [i ];
784
+ if (in_i != 0 ) {
785
+ return (i + 1 ) * sizeof (uint32_t ) - (uint32_nlz (in_i ) / 8 );
786
+ }
787
+ }
788
+
789
+ return 0 ;
790
+ }
0 commit comments