mirror of
https://github.com/ipxe/ipxe
synced 2025-12-13 15:31:42 +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:
@@ -208,13 +208,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* @v multiplicand Big integer to be multiplied
|
||||
* @v multiplier Big integer to be multiplied
|
||||
* @v result Big integer to hold result
|
||||
* @v carry Big integer to hold temporary carry space
|
||||
*/
|
||||
#define bigint_multiply( multiplicand, multiplier, result ) do { \
|
||||
#define bigint_multiply( multiplicand, multiplier, result, carry ) do { \
|
||||
unsigned int multiplicand_size = bigint_size (multiplicand); \
|
||||
unsigned int multiplier_size = bigint_size (multiplier); \
|
||||
bigint_multiply_raw ( (multiplicand)->element, \
|
||||
multiplicand_size, (multiplier)->element, \
|
||||
multiplier_size, (result)->element ); \
|
||||
multiplier_size, (result)->element, \
|
||||
(carry)->element ); \
|
||||
} while ( 0 )
|
||||
|
||||
/**
|
||||
@@ -245,7 +247,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
unsigned int size = bigint_size (modulus); \
|
||||
sizeof ( struct { \
|
||||
bigint_t ( size * 2 ) temp_result; \
|
||||
bigint_t ( size * 2 ) temp_modulus; \
|
||||
union { \
|
||||
bigint_t ( size * 2 ) temp_modulus; \
|
||||
bigint_t ( size * 2 ) temp_carry; \
|
||||
}; \
|
||||
} ); } )
|
||||
|
||||
/**
|
||||
@@ -311,11 +316,16 @@ void bigint_shrink_raw ( const bigint_element_t *source0,
|
||||
unsigned int dest_size );
|
||||
void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0,
|
||||
unsigned int size, int swap );
|
||||
void bigint_multiply_one ( const bigint_element_t multiplicand,
|
||||
const bigint_element_t multiplier,
|
||||
bigint_element_t *result,
|
||||
bigint_element_t *carry );
|
||||
void bigint_multiply_raw ( 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 );
|
||||
void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
|
||||
const bigint_element_t *multiplier0,
|
||||
const bigint_element_t *modulus0,
|
||||
|
||||
Reference in New Issue
Block a user