#ifndef _BITS_BIGINT_H #define _BITS_BIGINT_H /** @file * * Big integer support */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include /** Element of a big integer */ typedef uint64_t bigint_element_t; /** * Initialise big integer * * @v value0 Element 0 of big integer to initialise * @v size Number of elements * @v data Raw data * @v len Length of raw data */ static inline __attribute__ (( always_inline )) void bigint_init_raw ( uint64_t *value0, unsigned int size, const void *data, size_t len ) { size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len ); uint8_t *value_byte = ( ( void * ) value0 ); const uint8_t *data_byte = ( data + len ); /* Copy raw data in reverse order, padding with zeros */ while ( len-- ) *(value_byte++) = *(--data_byte); while ( pad_len-- ) *(value_byte++) = 0; } /** * Add big integers * * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements */ static inline __attribute__ (( always_inline )) void bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_addend; uint64_t *discard_value; uint64_t discard_addend_i; uint64_t discard_value_i; uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; __asm__ __volatile__ ( "\n1:\n\t" /* Load addend[i] and value[i] */ "ld.d %3, %0, 0\n\t" "ld.d %4, %1, 0\n\t" /* Add carry flag and addend */ "add.d %4, %4, %5\n\t" "sltu %6, %4, %5\n\t" "add.d %4, %4, %3\n\t" "sltu %5, %4, %3\n\t" "or %5, %5, %6\n\t" /* Store value[i] */ "st.d %4, %1, 0\n\t" /* Loop */ "addi.d %0, %0, 8\n\t" "addi.d %1, %1, 8\n\t" "addi.w %2, %2, -1\n\t" "bnez %2, 1b\n\t" : "=r" ( discard_addend ), "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_addend_i ), "=r" ( discard_value_i ), "=r" ( discard_carry ), "=r" ( discard_temp ), "+m" ( *value ) : "0" ( addend0 ), "1" ( value0 ), "2" ( size ), "5" ( 0 ) ); } /** * Subtract big integers * * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements */ static inline __attribute__ (( always_inline )) void bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_subtrahend; uint64_t *discard_value; uint64_t discard_subtrahend_i; uint64_t discard_value_i; uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; __asm__ __volatile__ ( "\n1:\n\t" /* Load subtrahend[i] and value[i] */ "ld.d %3, %0, 0\n\t" "ld.d %4, %1, 0\n\t" /* Subtract carry flag and subtrahend */ "sltu %6, %4, %5\n\t" "sub.d %4, %4, %5\n\t" "sltu %5, %4, %3\n\t" "sub.d %4, %4, %3\n\t" "or %5, %5, %6\n\t" /* Store value[i] */ "st.d %4, %1, 0\n\t" /* Loop */ "addi.d %0, %0, 8\n\t" "addi.d %1, %1, 8\n\t" "addi.w %2, %2, -1\n\t" "bnez %2, 1b\n\t" : "=r" ( discard_subtrahend ), "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_subtrahend_i ), "=r" ( discard_value_i ), "=r" ( discard_carry ), "=r" ( discard_temp ), "+m" ( *value ) : "0" ( subtrahend0 ), "1" ( value0 ), "2" ( size ), "5" ( 0 ) ); } /** * Rotate big integer left * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void bigint_rol_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; __asm__ __volatile__ ( "\n1:\n\t" /* Load value[i] */ "ld.d %2, %0, 0\n\t" /* Shift left */ "rotri.d %2, %2, 63\n\t" "andi %4, %2, 1\n\t" "xor %2, %2, %4\n\t" "or %2, %2, %3\n\t" "move %3, %4\n\t" /* Store value[i] */ "st.d %2, %0, 0\n\t" /* Loop */ "addi.d %0, %0, 8\n\t" "addi.w %1, %1, -1\n\t" "bnez %1, 1b\n\t" : "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_value_i ), "=r" ( discard_carry ), "=r" ( discard_temp ), "+m" ( *value ) : "0" ( value0 ), "1" ( size ), "3" ( 0 ) : "cc" ); } /** * Rotate big integer right * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void bigint_ror_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; __asm__ __volatile__ ( "\n1:\n\t" /* Load value[i] */ "ld.d %2, %0, -8\n\t" /* Shift right */ "andi %4, %2, 1\n\t" "xor %2, %2, %4\n\t" "or %2, %2, %3\n\t" "move %3, %4\n\t" "rotri.d %2, %2, 1\n\t" /* Store value[i] */ "st.d %2, %0, -8\n\t" /* Loop */ "addi.d %0, %0, -8\n\t" "addi.w %1, %1, -1\n\t" "bnez %1, 1b\n\t" : "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_value_i ), "=r" ( discard_carry ), "=r" ( discard_temp ), "+m" ( *value ) : "0" ( value0 + size ), "1" ( size ), "3" ( 0 ) : "cc" ); } /** * Test if big integer is equal to zero * * @v value0 Element 0 of big integer * @v size Number of elements * @ret is_zero Big integer is equal to zero */ static inline __attribute__ (( always_inline, pure )) int bigint_is_zero_raw ( const uint64_t *value0, unsigned int size ) { const uint64_t *value = value0; uint64_t value_i; do { value_i = *(value++); if ( value_i ) break; } while ( --size ); return ( value_i == 0 ); } /** * Compare big integers * * @v value0 Element 0 of big integer * @v reference0 Element 0 of reference big integer * @v size Number of elements * @ret geq Big integer is greater than or equal to the reference */ static inline __attribute__ (( always_inline, pure )) int bigint_is_geq_raw ( const uint64_t *value0, const uint64_t *reference0, unsigned int size ) { const uint64_t *value = ( value0 + size ); const uint64_t *reference = ( reference0 + size ); uint64_t value_i; uint64_t reference_i; do { value_i = *(--value); reference_i = *(--reference); if ( value_i != reference_i ) break; } while ( --size ); return ( value_i >= reference_i ); } /** * Test if bit is set in big integer * * @v value0 Element 0 of big integer * @v size Number of elements * @v bit Bit to test * @ret is_set Bit is set */ static inline __attribute__ (( always_inline )) int bigint_bit_is_set_raw ( const uint64_t *value0, unsigned int size, unsigned int bit ) { const bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( const void * ) value0 ); unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) ); unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) ); return ( !! ( value->element[index] & ( 1UL << subindex ) ) ); } /** * Find highest bit set in big integer * * @v value0 Element 0 of big integer * @v size Number of elements * @ret max_bit Highest bit set + 1 (or 0 if no bits set) */ static inline __attribute__ (( always_inline )) int bigint_max_set_bit_raw ( const uint64_t *value0, unsigned int size ) { const uint64_t *value = ( value0 + size ); int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) ); uint64_t value_i; do { value_i = *(--value); max_bit -= ( 64 - fls ( value_i ) ); if ( value_i ) break; } while ( --size ); return max_bit; } /** * Grow big integer * * @v source0 Element 0 of source big integer * @v source_size Number of elements in source big integer * @v dest0 Element 0 of destination big integer * @v dest_size Number of elements in destination big integer */ static inline __attribute__ (( always_inline )) void bigint_grow_raw ( const uint64_t *source0, unsigned int source_size, uint64_t *dest0, unsigned int dest_size ) { unsigned int pad_size = ( dest_size - source_size ); memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) ); memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) ); } /** * Shrink big integer * * @v source0 Element 0 of source big integer * @v source_size Number of elements in source big integer * @v dest0 Element 0 of destination big integer * @v dest_size Number of elements in destination big integer */ static inline __attribute__ (( always_inline )) void bigint_shrink_raw ( const uint64_t *source0, unsigned int source_size __unused, uint64_t *dest0, unsigned int dest_size ) { memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) ); } /** * Finalise big integer * * @v value0 Element 0 of big integer to finalise * @v size Number of elements * @v out Output buffer * @v len Length of output buffer */ static inline __attribute__ (( always_inline )) void bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, void *out, size_t len ) { const uint8_t *value_byte = ( ( const void * ) value0 ); uint8_t *out_byte = ( out + len ); /* Copy raw data in reverse order */ while ( len-- ) *(--out_byte) = *(value_byte++); } extern void bigint_multiply_raw ( const uint64_t *multiplicand0, unsigned int multiplicand_size, const uint64_t *multiplier0, unsigned int multiplier_size, uint64_t *value0 ); #endif /* _BITS_BIGINT_H */