mirror of
https://github.com/ipxe/ipxe
synced 2025-12-10 13:32:20 +03:00
[crypto] Use constant-time big integer multiplication
Big integer multiplication currently performs immediate carry propagation from each step of the long multiplication, relying on the fact that the overall result has a known maximum value to minimise the number of carries performed without ever needing to explicitly check against the result buffer size. This is not a constant-time algorithm, since the number of carries performed will be a function of the input values. We could make it constant-time by always continuing to propagate the carry until reaching the end of the result buffer, but this would introduce a large number of redundant zero carries. Require callers of bigint_multiply() to provide a temporary carry storage buffer, of the same size as the result buffer. This allows the carry-out from the accumulation of each double-element product to be accumulated in the temporary carry space, and then added in via a single call to bigint_add() after the multiplication is complete. Since the structure of big integer multiplication is identical across all current CPU architectures, provide a single shared implementation of bigint_multiply(). The architecture-specific operation then becomes the multiplication of two big integer elements and the accumulation of the double-element product. Note that any intermediate carry arising from accumulating the lower half of the double-element product may be added to the upper half of the double-element product without risk of overflow, since the result of multiplying two n-bit integers can never have all n bits set in its upper half. This simplifies the carry calculations for architectures such as RISC-V and LoongArch64 that do not have a carry flag. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -173,7 +173,8 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const bigint_element_t *multiplier0,
|
||||
unsigned int multiplier_size,
|
||||
bigint_element_t *result0 ) {
|
||||
bigint_element_t *result0,
|
||||
bigint_element_t *carry0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
@@ -181,8 +182,10 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0,
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*carry = ( ( void * ) carry0 );
|
||||
|
||||
bigint_multiply ( multiplicand, multiplier, result );
|
||||
bigint_multiply ( multiplicand, multiplier, result, carry );
|
||||
}
|
||||
|
||||
void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0,
|
||||
@@ -495,11 +498,14 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0,
|
||||
bigint_t ( multiplicand_size ) multiplicand_temp; \
|
||||
bigint_t ( multiplier_size ) multiplier_temp; \
|
||||
bigint_t ( multiplicand_size + multiplier_size ) result_temp; \
|
||||
bigint_t ( multiplicand_size + multiplier_size ) carry_temp; \
|
||||
{} /* Fix emacs alignment */ \
|
||||
\
|
||||
assert ( bigint_size ( &result_temp ) == \
|
||||
( bigint_size ( &multiplicand_temp ) + \
|
||||
bigint_size ( &multiplier_temp ) ) ); \
|
||||
assert ( bigint_size ( &carry_temp ) == \
|
||||
bigint_size ( &result_temp ) ); \
|
||||
bigint_init ( &multiplicand_temp, multiplicand_raw, \
|
||||
sizeof ( multiplicand_raw ) ); \
|
||||
bigint_init ( &multiplier_temp, multiplier_raw, \
|
||||
@@ -508,7 +514,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0,
|
||||
DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\
|
||||
DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \
|
||||
bigint_multiply ( &multiplicand_temp, &multiplier_temp, \
|
||||
&result_temp ); \
|
||||
&result_temp, &carry_temp ); \
|
||||
DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \
|
||||
bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\
|
||||
\
|
||||
|
||||
Reference in New Issue
Block a user