diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 4b37c062b..735fcdf61 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -287,27 +287,22 @@ void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, * @v invertend0 Element 0 of odd big integer to be inverted * @v inverse0 Element 0 of big integer to hold result * @v size Number of elements in invertend and result - * @v tmp Temporary working space */ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, - bigint_element_t *inverse0, - unsigned int size, void *tmp ) { + bigint_element_t *inverse0, unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *invertend = ( ( const void * ) invertend0 ); bigint_t ( size ) __attribute__ (( may_alias )) *inverse = ( ( void * ) inverse0 ); - struct { - bigint_t ( size ) residue; - } *temp = tmp; - const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); + bigint_element_t accum; + bigint_element_t bit; unsigned int i; /* Sanity check */ - assert ( invertend->element[0] & 1 ); + assert ( bigint_bit_is_set ( invertend, 0 ) ); - /* Initialise temporary working space and output value */ - memset ( &temp->residue, 0xff, sizeof ( temp->residue ) ); - memset ( inverse, 0, sizeof ( *inverse ) ); + /* Initialise output */ + memset ( inverse, 0xff, sizeof ( *inverse ) ); /* Compute inverse modulo 2^(width) * @@ -315,23 +310,47 @@ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, * presented in "A New Algorithm for Inversion mod p^k (Koç, * 2017)". * - * Each loop iteration calculates one bit of the inverse. The - * residue value is the two's complement negation of the value - * "b" as used by Koç, to allow for division by two using a - * logical right shift (since we have no arithmetic right - * shift operation for big integers). + * Each inner loop iteration calculates one bit of the + * inverse. The residue value is the two's complement + * negation of the value "b" as used by Koç, to allow for + * division by two using a logical right shift (since we have + * no arithmetic right shift operation for big integers). + * + * The residue is stored in the as-yet uncalculated portion of + * the inverse. The size of the residue therefore decreases + * by one element for each outer loop iteration. Trivial + * inspection of the algorithm shows that any higher bits + * could not contribute to the eventual output value, and so + * we may safely reuse storage this way. * * Due to the suffix property of inverses mod 2^k, the result * represents the least significant bits of the inverse modulo * an arbitrarily large 2^k. */ - for ( i = 0 ; i < ( 8 * sizeof ( *inverse ) ) ; i++ ) { - if ( temp->residue.element[0] & 1 ) { - inverse->element[ i / width ] |= - ( 1UL << ( i % width ) ); - bigint_add ( invertend, &temp->residue ); + for ( i = size ; i > 0 ; i-- ) { + const bigint_t ( i ) __attribute__ (( may_alias )) + *addend = ( ( const void * ) invertend ); + bigint_t ( i ) __attribute__ (( may_alias )) + *residue = ( ( void * ) inverse ); + + /* Calculate one element's worth of inverse bits */ + for ( accum = 0, bit = 1 ; bit ; bit <<= 1 ) { + if ( bigint_bit_is_set ( residue, 0 ) ) { + accum |= bit; + bigint_add ( addend, residue ); + } + bigint_shr ( residue ); } - bigint_shr ( &temp->residue ); + + /* Store in the element no longer required to hold residue */ + inverse->element[ i - 1 ] = accum; + } + + /* Correct order of inverse elements */ + for ( i = 0 ; i < ( size / 2 ) ; i++ ) { + accum = inverse->element[i]; + inverse->element[i] = inverse->element[ size - 1 - i ]; + inverse->element[ size - 1 - i ] = accum; } } diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 330d7deec..e55c536c7 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -242,30 +242,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); } while ( 0 ) /** - * Compute inverse of odd big integer modulo its own size + * Compute inverse of odd big integer modulo any power of two * * @v invertend Odd big integer to be inverted * @v inverse Big integer to hold result - * @v tmp Temporary working space */ -#define bigint_mod_invert( invertend, inverse, tmp ) do { \ - unsigned int size = bigint_size (invertend); \ +#define bigint_mod_invert( invertend, inverse ) do { \ + unsigned int size = bigint_size ( invertend ); \ bigint_mod_invert_raw ( (invertend)->element, \ - (inverse)->element, size, tmp ); \ + (inverse)->element, size ); \ } while ( 0 ) -/** - * Calculate temporary working space required for modular inversion - * - * @v invertend Odd big integer to be inverted - * @ret len Length of temporary working space - */ -#define bigint_mod_invert_tmp_len( invertend ) ( { \ - unsigned int size = bigint_size (invertend); \ - sizeof ( struct { \ - bigint_t ( size ) temp_residue; \ - } ); } ) - /** * Perform modular multiplication of big integers * @@ -408,8 +395,7 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, unsigned int size ); void bigint_mod_invert_raw ( const bigint_element_t *invertend0, - bigint_element_t *inverse0, - unsigned int size, void *tmp ); + bigint_element_t *inverse0, unsigned int size ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 61f78fff9..608d8e874 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -197,13 +197,13 @@ void bigint_reduce_sample ( bigint_element_t *modulus0, void bigint_mod_invert_sample ( const bigint_element_t *invertend0, bigint_element_t *inverse0, - unsigned int size, void *tmp ) { + unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *invertend = ( ( const void * ) invertend0 ); bigint_t ( size ) __attribute__ (( may_alias )) *inverse = ( ( void * ) inverse0 ); - bigint_mod_invert ( invertend, inverse, tmp ); + bigint_mod_invert ( invertend, inverse ); } void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, @@ -600,8 +600,6 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_required_size ( sizeof ( invertend_raw ) ); \ bigint_t ( size ) invertend_temp; \ bigint_t ( size ) inverse_temp; \ - size_t tmp_len = bigint_mod_invert_tmp_len ( &invertend_temp ); \ - uint8_t tmp[tmp_len]; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &invertend_temp ) == \ @@ -610,7 +608,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, sizeof ( invertend_raw ) ); \ DBG ( "Modular invert:\n" ); \ DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) ); \ - bigint_mod_invert ( &invertend_temp, &inverse_temp, tmp ); \ + bigint_mod_invert ( &invertend_temp, &inverse_temp ); \ DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) ); \ bigint_done ( &inverse_temp, inverse_raw, \ sizeof ( inverse_raw ) ); \ @@ -1827,6 +1825,10 @@ static void bigint_test_exec ( void ) { 0xff, 0xff ), BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ) ); + bigint_mod_invert_ok ( BIGINT ( 0xa4, 0xcb, 0xbc, 0xc9, 0x9f, 0x7a, + 0x65, 0xbf ), + BIGINT ( 0xb9, 0xd5, 0xf4, 0x88, 0x0b, 0xf8, + 0x8a, 0x3f ) ); bigint_mod_invert_ok ( BIGINT ( 0x95, 0x6a, 0xc5, 0xe7, 0x2e, 0x5b, 0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d, 0xf4, 0x5a, 0x48, 0xc1 ), @@ -1839,6 +1841,18 @@ static void bigint_test_exec ( void ) { BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4, 0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf, 0x5f, 0xe2, 0x21, 0xcd ) ); + bigint_mod_invert_ok ( BIGINT ( 0xb9, 0xbb, 0x7f, 0x9c, 0x7a, 0x32, + 0x43, 0xed, 0x9d, 0xd4, 0x0d, 0x6f, + 0x32, 0xfa, 0x4b, 0x62, 0x38, 0x3a, + 0xbf, 0x4c, 0xbd, 0xa8, 0x47, 0xce, + 0xa2, 0x30, 0x34, 0xe0, 0x2c, 0x09, + 0x14, 0x89 ), + BIGINT ( 0xfc, 0x05, 0xc4, 0x2a, 0x90, 0x99, + 0x82, 0xf8, 0x81, 0x1d, 0x87, 0xb8, + 0xca, 0xe4, 0x95, 0xe2, 0xac, 0x18, + 0xb3, 0xe1, 0x3e, 0xc6, 0x5a, 0x03, + 0x51, 0x6f, 0xb7, 0xe3, 0xa5, 0xd6, + 0xa1, 0xb9 ) ); bigint_mod_multiply_ok ( BIGINT ( 0x37 ), BIGINT ( 0x67 ), BIGINT ( 0x3f ),