Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizated calculation of shared power of 2 in bn_gcd #24332

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 22 additions & 11 deletions crypto/bn/bn_gcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "internal/cryptlib.h"
#include "bn_local.h"
#include "internal/constant_time.h"

/*
* bn_mod_inverse_no_branch is a special version of BN_mod_inverse. It does
Expand Down Expand Up @@ -580,8 +581,8 @@ int BN_are_coprime(BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
{
BIGNUM *g, *temp = NULL;
BN_ULONG mask = 0;
int i, j, top, rlen, glen, m, bit = 1, delta = 1, cond = 0, shifts = 0, ret = 0;
BN_ULONG pow2_numbits, pow2_numbits_temp, pow2_condition_mask;
int i, j, top, rlen, glen, m, delta = 1, cond = 0, pow2_shifts, ret = 0, pow2_flag;
landgrafhomyak marked this conversation as resolved.
Show resolved Hide resolved

/* Note 2: zero input corner cases are not constant-time since they are
* handled immediately. An attacker can run an attack under this
Expand Down Expand Up @@ -611,18 +612,28 @@ int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
goto err;

/* find shared powers of two, i.e. "shifts" >= 1 */
pow2_flag = 1;
pow2_shifts = 0;
pow2_numbits = 0;
for (i = 0; i < r->dmax && i < g->dmax; i++) {
mask = ~(r->d[i] | g->d[i]);
for (j = 0; j < BN_BITS2; j++) {
bit &= mask;
shifts += bit;
mask >>= 1;
}
pow2_numbits_temp = r->d[i] | g->d[i];
pow2_condition_mask = ~(constant_time_is_zero_bn(pow2_flag)) & ~(constant_time_is_zero_bn(pow2_numbits_temp));
pow2_flag &= ~pow2_condition_mask;
bernd-edlinger marked this conversation as resolved.
Show resolved Hide resolved
pow2_shifts += 1 & pow2_flag;
landgrafhomyak marked this conversation as resolved.
Show resolved Hide resolved
pow2_numbits = constant_time_select_bn(pow2_condition_mask, pow2_numbits_temp, pow2_numbits);
}
pow2_numbits = ~pow2_numbits;
pow2_shifts *= BN_BITS2;
pow2_flag = 1;
for (j = 0; j < BN_BITS2; j++) {
pow2_flag &= pow2_numbits;
landgrafhomyak marked this conversation as resolved.
Show resolved Hide resolved
pow2_shifts += pow2_flag;
pow2_numbits >>= 1;
}

/* subtract shared powers of two; shifts >= 1 */
if (!BN_rshift(r, r, shifts)
|| !BN_rshift(g, g, shifts))
if (!BN_rshift(r, r, pow2_shifts)
|| !BN_rshift(g, g, pow2_shifts))
goto err;

/* expand to biggest nword, with room for a possible extra word */
Expand Down Expand Up @@ -665,7 +676,7 @@ int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
/* remove possible negative sign */
r->neg = 0;
/* add powers of 2 removed, then correct the artificial shift */
if (!BN_lshift(r, r, shifts)
if (!BN_lshift(r, r, pow2_shifts)
|| !BN_rshift1(r, r))
goto err;

Expand Down
18 changes: 18 additions & 0 deletions include/internal/constant_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)
}

#ifdef BN_ULONG
static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a)
{
#if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
BN_ULONG r;
__asm__("" : "=r"(r) : "0"(a));
#else
volatile BN_ULONG r = a;
#endif
return r;
}

static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)
{
return 0 - (a >> (sizeof(a) * 8 - 1));
Expand All @@ -161,6 +172,13 @@ static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,
{
return constant_time_is_zero_bn(a ^ b);
}

static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask,
BN_ULONG a,
BN_ULONG b)
{
return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b);
}
#endif

static ossl_inline unsigned int constant_time_ge(unsigned int a,
Expand Down