mirror of https://github.com/ipxe/ipxe.git
[crypto] Eliminate temporary working space for bigint_mod_invert()
With a slight modification to the algorithm to ignore bits of the residue that can never contribute to the result, it is possible to reuse the as-yet uncalculated portions of the inverse to hold the residue. This removes the requirement for additional temporary working space. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/1351/head
parent
9cbf5c4f86
commit
7c2e68cc87
|
@ -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 invertend0 Element 0 of odd big integer to be inverted
|
||||||
* @v inverse0 Element 0 of big integer to hold result
|
* @v inverse0 Element 0 of big integer to hold result
|
||||||
* @v size Number of elements in invertend and 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,
|
void bigint_mod_invert_raw ( const bigint_element_t *invertend0,
|
||||||
bigint_element_t *inverse0,
|
bigint_element_t *inverse0, unsigned int size ) {
|
||||||
unsigned int size, void *tmp ) {
|
|
||||||
const bigint_t ( size ) __attribute__ (( may_alias ))
|
const bigint_t ( size ) __attribute__ (( may_alias ))
|
||||||
*invertend = ( ( const void * ) invertend0 );
|
*invertend = ( ( const void * ) invertend0 );
|
||||||
bigint_t ( size ) __attribute__ (( may_alias ))
|
bigint_t ( size ) __attribute__ (( may_alias ))
|
||||||
*inverse = ( ( void * ) inverse0 );
|
*inverse = ( ( void * ) inverse0 );
|
||||||
struct {
|
bigint_element_t accum;
|
||||||
bigint_t ( size ) residue;
|
bigint_element_t bit;
|
||||||
} *temp = tmp;
|
|
||||||
const unsigned int width = ( 8 * sizeof ( bigint_element_t ) );
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
assert ( invertend->element[0] & 1 );
|
assert ( bigint_bit_is_set ( invertend, 0 ) );
|
||||||
|
|
||||||
/* Initialise temporary working space and output value */
|
/* Initialise output */
|
||||||
memset ( &temp->residue, 0xff, sizeof ( temp->residue ) );
|
memset ( inverse, 0xff, sizeof ( *inverse ) );
|
||||||
memset ( inverse, 0, sizeof ( *inverse ) );
|
|
||||||
|
|
||||||
/* Compute inverse modulo 2^(width)
|
/* 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ç,
|
* presented in "A New Algorithm for Inversion mod p^k (Koç,
|
||||||
* 2017)".
|
* 2017)".
|
||||||
*
|
*
|
||||||
* Each loop iteration calculates one bit of the inverse. The
|
* Each inner loop iteration calculates one bit of the
|
||||||
* residue value is the two's complement negation of the value
|
* inverse. The residue value is the two's complement
|
||||||
* "b" as used by Koç, to allow for division by two using a
|
* negation of the value "b" as used by Koç, to allow for
|
||||||
* logical right shift (since we have no arithmetic right
|
* division by two using a logical right shift (since we have
|
||||||
* shift operation for big integers).
|
* 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
|
* Due to the suffix property of inverses mod 2^k, the result
|
||||||
* represents the least significant bits of the inverse modulo
|
* represents the least significant bits of the inverse modulo
|
||||||
* an arbitrarily large 2^k.
|
* an arbitrarily large 2^k.
|
||||||
*/
|
*/
|
||||||
for ( i = 0 ; i < ( 8 * sizeof ( *inverse ) ) ; i++ ) {
|
for ( i = size ; i > 0 ; i-- ) {
|
||||||
if ( temp->residue.element[0] & 1 ) {
|
const bigint_t ( i ) __attribute__ (( may_alias ))
|
||||||
inverse->element[ i / width ] |=
|
*addend = ( ( const void * ) invertend );
|
||||||
( 1UL << ( i % width ) );
|
bigint_t ( i ) __attribute__ (( may_alias ))
|
||||||
bigint_add ( invertend, &temp->residue );
|
*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 ( &temp->residue );
|
bigint_shr ( 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -242,30 +242,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
} while ( 0 )
|
} 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 invertend Odd big integer to be inverted
|
||||||
* @v inverse Big integer to hold result
|
* @v inverse Big integer to hold result
|
||||||
* @v tmp Temporary working space
|
|
||||||
*/
|
*/
|
||||||
#define bigint_mod_invert( invertend, inverse, tmp ) do { \
|
#define bigint_mod_invert( invertend, inverse ) do { \
|
||||||
unsigned int size = bigint_size (invertend); \
|
unsigned int size = bigint_size ( invertend ); \
|
||||||
bigint_mod_invert_raw ( (invertend)->element, \
|
bigint_mod_invert_raw ( (invertend)->element, \
|
||||||
(inverse)->element, size, tmp ); \
|
(inverse)->element, size ); \
|
||||||
} while ( 0 )
|
} 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
|
* 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,
|
void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0,
|
||||||
unsigned int size );
|
unsigned int size );
|
||||||
void bigint_mod_invert_raw ( const bigint_element_t *invertend0,
|
void bigint_mod_invert_raw ( const bigint_element_t *invertend0,
|
||||||
bigint_element_t *inverse0,
|
bigint_element_t *inverse0, unsigned int size );
|
||||||
unsigned int size, void *tmp );
|
|
||||||
void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
|
void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
|
||||||
const bigint_element_t *multiplier0,
|
const bigint_element_t *multiplier0,
|
||||||
const bigint_element_t *modulus0,
|
const bigint_element_t *modulus0,
|
||||||
|
|
|
@ -197,13 +197,13 @@ void bigint_reduce_sample ( bigint_element_t *modulus0,
|
||||||
|
|
||||||
void bigint_mod_invert_sample ( const bigint_element_t *invertend0,
|
void bigint_mod_invert_sample ( const bigint_element_t *invertend0,
|
||||||
bigint_element_t *inverse0,
|
bigint_element_t *inverse0,
|
||||||
unsigned int size, void *tmp ) {
|
unsigned int size ) {
|
||||||
const bigint_t ( size ) __attribute__ (( may_alias ))
|
const bigint_t ( size ) __attribute__ (( may_alias ))
|
||||||
*invertend = ( ( const void * ) invertend0 );
|
*invertend = ( ( const void * ) invertend0 );
|
||||||
bigint_t ( size ) __attribute__ (( may_alias ))
|
bigint_t ( size ) __attribute__ (( may_alias ))
|
||||||
*inverse = ( ( void * ) inverse0 );
|
*inverse = ( ( void * ) inverse0 );
|
||||||
|
|
||||||
bigint_mod_invert ( invertend, inverse, tmp );
|
bigint_mod_invert ( invertend, inverse );
|
||||||
}
|
}
|
||||||
|
|
||||||
void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0,
|
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_required_size ( sizeof ( invertend_raw ) ); \
|
||||||
bigint_t ( size ) invertend_temp; \
|
bigint_t ( size ) invertend_temp; \
|
||||||
bigint_t ( size ) inverse_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 */ \
|
{} /* Fix emacs alignment */ \
|
||||||
\
|
\
|
||||||
assert ( bigint_size ( &invertend_temp ) == \
|
assert ( bigint_size ( &invertend_temp ) == \
|
||||||
|
@ -610,7 +608,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0,
|
||||||
sizeof ( invertend_raw ) ); \
|
sizeof ( invertend_raw ) ); \
|
||||||
DBG ( "Modular invert:\n" ); \
|
DBG ( "Modular invert:\n" ); \
|
||||||
DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) ); \
|
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 ) ); \
|
DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) ); \
|
||||||
bigint_done ( &inverse_temp, inverse_raw, \
|
bigint_done ( &inverse_temp, inverse_raw, \
|
||||||
sizeof ( inverse_raw ) ); \
|
sizeof ( inverse_raw ) ); \
|
||||||
|
@ -1827,6 +1825,10 @@ static void bigint_test_exec ( void ) {
|
||||||
0xff, 0xff ),
|
0xff, 0xff ),
|
||||||
BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
BIGINT ( 0xff, 0xff, 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,
|
bigint_mod_invert_ok ( BIGINT ( 0x95, 0x6a, 0xc5, 0xe7, 0x2e, 0x5b,
|
||||||
0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d,
|
0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d,
|
||||||
0xf4, 0x5a, 0x48, 0xc1 ),
|
0xf4, 0x5a, 0x48, 0xc1 ),
|
||||||
|
@ -1839,6 +1841,18 @@ static void bigint_test_exec ( void ) {
|
||||||
BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4,
|
BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4,
|
||||||
0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf,
|
0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf,
|
||||||
0x5f, 0xe2, 0x21, 0xcd ) );
|
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_mod_multiply_ok ( BIGINT ( 0x37 ),
|
||||||
BIGINT ( 0x67 ),
|
BIGINT ( 0x67 ),
|
||||||
BIGINT ( 0x3f ),
|
BIGINT ( 0x3f ),
|
||||||
|
|
Loading…
Reference in New Issue