Skip to content

Commit

Permalink
[crypto] Use constant-time big integer multiplication
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
mcb30 committed Sep 23, 2024
1 parent 59d1236 commit 3def132
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 612 deletions.
106 changes: 0 additions & 106 deletions src/arch/arm32/core/arm32_bigint.c

This file was deleted.

34 changes: 29 additions & 5 deletions src/arch/arm32/include/bits/bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,34 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
*(--out_byte) = *(value_byte++);
}

extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
unsigned int multiplicand_size,
const uint32_t *multiplier0,
unsigned int multiplier_size,
uint32_t *value0 );
/**
* Multiply big integer elements
*
* @v multiplicand Multiplicand element
* @v multiplier Multiplier element
* @v result Result element pair
* @v carry Carry element
*/
static inline __attribute__ (( always_inline )) void
bigint_multiply_one ( const uint32_t multiplicand, const uint32_t multiplier,
uint32_t *result, uint32_t *carry ) {
uint32_t discard_low;
uint32_t discard_high;

__asm__ __volatile__ ( /* Perform multiplication */
"umull %0, %1, %5, %6\n\t"
/* Accumulate result */
"adds %2, %0\n\t"
"adcs %3, %1\n\t"
/* Accumulate carry (cannot overflow) */
"adc %4, #0\n\t"
: "=r" ( discard_low ),
"=r" ( discard_high ),
"+r" ( result[0] ),
"+r" ( result[1] ),
"+r" ( *carry )
: "r" ( multiplicand ),
"r" ( multiplier ) );
}

#endif /* _BITS_BIGINT_H */
107 changes: 0 additions & 107 deletions src/arch/arm64/core/arm64_bigint.c

This file was deleted.

35 changes: 30 additions & 5 deletions src/arch/arm64/include/bits/bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,35 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
*(--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 );
/**
* Multiply big integer elements
*
* @v multiplicand Multiplicand element
* @v multiplier Multiplier element
* @v result Result element pair
* @v carry Carry element
*/
static inline __attribute__ (( always_inline )) void
bigint_multiply_one ( const uint64_t multiplicand, const uint64_t multiplier,
uint64_t *result, uint64_t *carry ) {
uint64_t discard_low;
uint64_t discard_high;

__asm__ __volatile__ ( /* Perform multiplication */
"mul %0, %5, %6\n\t"
"umulh %1, %5, %6\n\t"
/* Accumulate result */
"adds %2, %2, %0\n\t"
"adcs %3, %3, %1\n\t"
/* Accumulate carry (cannot overflow) */
"adc %4, %4, xzr\n\t"
: "=&r" ( discard_low ),
"=r" ( discard_high ),
"+r" ( result[0] ),
"+r" ( result[1] ),
"+r" ( *carry )
: "r" ( multiplicand ),
"r" ( multiplier ) );
}

#endif /* _BITS_BIGINT_H */
Loading

0 comments on commit 3def132

Please sign in to comment.