]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Optimizated calculation of shared power of 2 in bn_gcd
authorAndrew Golovashevich <tankist.scratch.p@gmail.com>
Sun, 5 May 2024 11:27:26 +0000 (14:27 +0300)
committerTomas Mraz <tomas@openssl.org>
Wed, 15 May 2024 11:37:48 +0000 (13:37 +0200)
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24332)

crypto/bn/bn_gcd.c
include/internal/constant_time.h

index 2cd8ee35e034a38f1200e25a38d5dfb180cd0189..fd6cf9d8f731d3690eb55a46d055461012deed8a 100644 (file)
@@ -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
@@ -580,8 +581,8 @@ end:
 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, pow2_flag;
+    int i, j, top, rlen, glen, m, delta = 1, cond = 0, pow2_shifts, ret = 0;
 
     /* Note 2: zero input corner cases are not constant-time since they are
      * handled immediately. An attacker can run an attack under this
@@ -611,18 +612,29 @@ 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);
+        pow2_flag &= constant_time_is_zero_bn(pow2_numbits_temp);
+        pow2_shifts += pow2_flag;
+        pow2_numbits = constant_time_select_bn(pow2_condition_mask,
+                                               pow2_numbits, pow2_numbits_temp);
+    }
+    pow2_numbits = ~pow2_numbits;
+    pow2_shifts *= BN_BITS2;
+    pow2_flag = 1;
+    for (j = 0; j < BN_BITS2; j++) {
+        pow2_flag &= pow2_numbits;
+        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 */
@@ -665,7 +677,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;
 
index f2572ded519984ecb76ec1610224cf0aa5a55883..9ffa4399a357f976ba1651d6568cf6b9bd1390e7 100644 (file)
@@ -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));
@@ -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,