Make BN_generate_dsa_nonce internally constant-time.
This rewrites the internals with a "words" variant that can avoid
bn_correct_top. It still ultimately calls bn_correct_top as the calling
convention is sadly still BIGNUM, but we can lift that calling
convention out incrementally.
Performance seems to be comparable, if not faster.
Before:
Did 85000 ECDSA P-256 signing operations in 5030401us (16897.3 ops/sec)
Did 34278 ECDSA P-256 verify operations in 5048029us (6790.4 ops/sec)
After:
Did 85000 ECDSA P-256 signing operations in 5021057us (16928.7 ops/sec)
Did 34086 ECDSA P-256 verify operations in 5010416us (6803.0 ops/sec)
Change-Id: I1159746dfcc00726dc3f28396076a354556e6e7d
Reviewed-on: https://boringssl-review.googlesource.com/23065
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/bn/bn_test.cc b/crypto/fipsmodule/bn/bn_test.cc
index 975264e..5725eaa 100644
--- a/crypto/fipsmodule/bn/bn_test.cc
+++ b/crypto/fipsmodule/bn/bn_test.cc
@@ -93,6 +93,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
+#include "./internal.h"
#include "../../internal.h"
#include "../../test/file_test.h"
#include "../../test/test_util.h"
@@ -1618,3 +1619,94 @@
nullptr /* callback */));
EXPECT_EQ(0, is_probably_prime_2);
}
+
+#if !defined(BORINGSSL_SHARED_LIBRARY)
+TEST_F(BNTest, LessThanWords) {
+ // kTestVectors is an array of 256-bit values in sorted order.
+ static const BN_ULONG kTestVectors[][256 / BN_BITS2] = {
+ {TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0x00000002), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0x0000ffff), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0xfffffffe), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0xffffffff), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0xed17ac85, 0x83339914), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000001),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
+ TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
+ TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000)},
+ {TOBN(0x00000000, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0x00000000, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0xed17ac85, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0xed17ac85, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0xffffffff, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0xffffffff, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
+ TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
+ {TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
+ TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff)},
+ {TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
+ TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
+ {TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
+ TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
+ {TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff),
+ TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
+ {TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
+ TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
+ };
+
+ // Determine where the single-word values stop.
+ size_t one_word;
+ for (one_word = 0; one_word < OPENSSL_ARRAY_SIZE(kTestVectors); one_word++) {
+ int is_word = 1;
+ for (size_t i = 1; i < OPENSSL_ARRAY_SIZE(kTestVectors[one_word]); i++) {
+ if (kTestVectors[one_word][i] != 0) {
+ is_word = 0;
+ break;
+ }
+ }
+ if (!is_word) {
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) {
+ SCOPED_TRACE(i);
+ for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kTestVectors); j++) {
+ SCOPED_TRACE(j);
+ EXPECT_EQ(i < j ? 1 : 0,
+ bn_less_than_words(kTestVectors[i], kTestVectors[j],
+ OPENSSL_ARRAY_SIZE(kTestVectors[i])));
+ for (size_t k = 0; k < one_word; k++) {
+ SCOPED_TRACE(k);
+ EXPECT_EQ(k <= i && i < j ? 1 : 0,
+ bn_in_range_words(kTestVectors[i], kTestVectors[k][0],
+ kTestVectors[j],
+ OPENSSL_ARRAY_SIZE(kTestVectors[i])));
+ }
+ }
+ }
+
+ EXPECT_EQ(0, bn_less_than_words(NULL, NULL, 0));
+ EXPECT_EQ(0, bn_in_range_words(NULL, 0, NULL, 0));
+}
+#endif // !BORINGSSL_SHARED_LIBRARY
diff --git a/crypto/fipsmodule/bn/cmp.c b/crypto/fipsmodule/bn/cmp.c
index 7864707..acc017f 100644
--- a/crypto/fipsmodule/bn/cmp.c
+++ b/crypto/fipsmodule/bn/cmp.c
@@ -57,8 +57,10 @@
#include <openssl/bn.h>
#include <openssl/mem.h>
+#include <openssl/type_check.h>
#include "internal.h"
+#include "../../internal.h"
int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
@@ -174,6 +176,19 @@
return bn_cmp_words(a, b, cl);
}
+int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
+ OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
+ crypto_word_t_too_small);
+ int ret = 0;
+ // Process the words in little-endian order.
+ for (size_t i = 0; i < len; i++) {
+ crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
+ crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
+ ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
+ }
+ return ret;
+}
+
int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
switch (bn->top) {
case 1:
diff --git a/crypto/fipsmodule/bn/internal.h b/crypto/fipsmodule/bn/internal.h
index acc0ac8..57cf755 100644
--- a/crypto/fipsmodule/bn/internal.h
+++ b/crypto/fipsmodule/bn/internal.h
@@ -265,6 +265,18 @@
// the length of |a| minus the length of |b|.
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
+// bn_less_than_words returns one if |a| < |b| and zero otherwise, where |a|
+// and |b| both are |len| words long. It runs in constant time.
+int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len);
+
+// bn_in_range_words returns one if |min_inclusive| <= |a| < |max_exclusive|,
+// where |a| and |max_exclusive| both are |len| words long. This function leaks
+// which of [0, min_inclusive), [min_inclusive, max_exclusive), and
+// [max_exclusive, 2^(BN_BITS2*len)) contains |a|, but otherwise the value of
+// |a| is secret.
+int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive,
+ const BN_ULONG *max_exclusive, size_t len);
+
int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
const BN_ULONG *np, const BN_ULONG *n0, int num);
diff --git a/crypto/fipsmodule/bn/random.c b/crypto/fipsmodule/bn/random.c
index 2257da0..60d1bb0 100644
--- a/crypto/fipsmodule/bn/random.c
+++ b/crypto/fipsmodule/bn/random.c
@@ -122,9 +122,7 @@
static const uint8_t kDefaultAdditionalData[32] = {0};
-static int bn_rand_with_additional_data(BIGNUM *rnd, int bits, int top,
- int bottom,
- const uint8_t additional_data[32]) {
+int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
uint8_t *buf = NULL;
int ret = 0, bit, bytes, mask;
@@ -159,7 +157,7 @@
}
// Make a random number and set the top and bottom bits.
- RAND_bytes_with_additional_data(buf, bytes, additional_data);
+ RAND_bytes(buf, bytes);
if (top != BN_RAND_TOP_ANY) {
if (top == BN_RAND_TOP_TWO && bits > 1) {
@@ -192,47 +190,114 @@
return ret;
}
-int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
- return bn_rand_with_additional_data(rnd, bits, top, bottom,
- kDefaultAdditionalData);
-}
-
int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) {
return BN_rand(rnd, bits, top, bottom);
}
-static int bn_rand_range_with_additional_data(
- BIGNUM *r, BN_ULONG min_inclusive, const BIGNUM *max_exclusive,
- const uint8_t additional_data[32]) {
- if (BN_cmp_word(max_exclusive, min_inclusive) <= 0) {
+// bn_less_than_word returns one if the number represented by |len| words at |a|
+// is less than |b| and zero otherwise. It performs this computation in time
+// independent of the value of |a|. |b| is assumed public.
+static int bn_less_than_word(const BN_ULONG *a, size_t len, BN_ULONG b) {
+ if (b == 0) {
+ return 0;
+ }
+ if (len == 0) {
+ return 1;
+ }
+
+ // |a| < |b| iff a[1..len-1] are all zero and a[0] < b.
+ OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
+ crypto_word_t_too_small);
+ crypto_word_t mask = 0;
+ for (size_t i = 1; i < len; i++) {
+ mask |= a[i];
+ }
+ // |mask| is now zero iff a[1..len-1] are all zero.
+ mask = constant_time_is_zero_w(mask);
+ mask &= constant_time_lt_w(a[0], b);
+ return constant_time_select_int(mask, 1, 0);
+}
+
+int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive,
+ const BN_ULONG *max_exclusive, size_t len) {
+ return bn_less_than_words(a, max_exclusive, len) &&
+ !bn_less_than_word(a, len, min_inclusive);
+}
+
+// bn_rand_range_words sets |out| to a uniformly distributed random number from
+// |min_inclusive| to |max_exclusive|. Both |out| and |max_exclusive| are |len|
+// words long.
+//
+// This function runs in time independent of the result, but |min_inclusive| and
+// |max_exclusive| are public data. (Information about the range is unavoidably
+// leaked by how many iterations it took to select a number.)
+static int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
+ const BN_ULONG *max_exclusive, size_t len,
+ const uint8_t additional_data[32]) {
+ // This function implements the equivalent of steps 4 through 7 of FIPS 186-4
+ // appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive|
+ // is n and |min_inclusive| is one.
+
+ // Compute the bit length of |max_exclusive| (step 1), in terms of a number of
+ // |words| worth of entropy to fill and a mask of bits to clear in the top
+ // word.
+ size_t words = len;
+ while (words > 0 && max_exclusive[words - 1] == 0) {
+ words--;
+ }
+ if (words == 0 ||
+ (words == 1 && max_exclusive[0] <= min_inclusive)) {
OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
return 0;
}
+ BN_ULONG mask = max_exclusive[words - 1];
+ // This sets all bits in |mask| below the most significant bit.
+ mask |= mask >> 1;
+ mask |= mask >> 2;
+ mask |= mask >> 4;
+ mask |= mask >> 8;
+ mask |= mask >> 16;
+#if defined(OPENSSL_64_BIT)
+ mask |= mask >> 32;
+#endif
- // This function is used to implement steps 4 through 7 of FIPS 186-4
- // appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive|
- // is n and |min_inclusive| is one.
+ // Fill any unused words with zero.
+ OPENSSL_memset(out + words, 0, (len - words) * sizeof(BN_ULONG));
+
unsigned count = 100;
- unsigned n = BN_num_bits(max_exclusive); // n > 0
do {
if (!--count) {
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
return 0;
}
- if (// steps 4 and 5
- !bn_rand_with_additional_data(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY,
- additional_data) ||
- // step 7
- !BN_add_word(r, min_inclusive)) {
- return 0;
- }
+ // Steps 4 and 5. Use |words| and |mask| together to obtain a string of N
+ // bits, where N is the bit length of |max_exclusive|.
+ RAND_bytes_with_additional_data((uint8_t *)out, words * sizeof(BN_ULONG),
+ additional_data);
+ out[words - 1] &= mask;
- // Step 6. This loops if |r| >= |max_exclusive|. This is identical to
- // checking |r| > |max_exclusive| - 1 or |r| - 1 > |max_exclusive| - 2, the
- // formulation stated in FIPS 186-4.
- } while (BN_cmp(r, max_exclusive) >= 0);
+ // If out >= max_exclusive or out < min_inclusive, retry. This implements
+ // the equivalent of steps 6 and 7 without leaking the value of |out|.
+ } while (!bn_in_range_words(out, min_inclusive, max_exclusive, words));
+ return 1;
+}
+static int bn_rand_range_with_additional_data(
+ BIGNUM *r, BN_ULONG min_inclusive, const BIGNUM *max_exclusive,
+ const uint8_t additional_data[32]) {
+ if (!bn_wexpand(r, max_exclusive->top) ||
+ !bn_rand_range_words(r->d, min_inclusive, max_exclusive->d,
+ max_exclusive->top, additional_data)) {
+ return 0;
+ }
+
+ // TODO(davidben): |bn_correct_top| is not constant-time. Make
+ // |BN_generate_dsa_nonce| call |bn_rand_range_words| directly and then inline
+ // this function into |BN_rand_range_ex|.
+ r->neg = 0;
+ r->top = max_exclusive->top;
+ bn_correct_top(r);
return 1;
}
diff --git a/crypto/fipsmodule/rsa/internal.h b/crypto/fipsmodule/rsa/internal.h
index 67f2cb9..0f0c763 100644
--- a/crypto/fipsmodule/rsa/internal.h
+++ b/crypto/fipsmodule/rsa/internal.h
@@ -119,10 +119,6 @@
extern const BN_ULONG kBoringSSLRSASqrtTwo[];
extern const size_t kBoringSSLRSASqrtTwoLen;
-// rsa_less_than_words returns one if |a| < |b| and zero otherwise, where |a|
-// and |b| both are |len| words long. It runs in constant time.
-int rsa_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len);
-
// rsa_greater_than_pow2 returns one if |b| is greater than 2^|n| and zero
// otherwise.
int rsa_greater_than_pow2(const BIGNUM *b, int n);
diff --git a/crypto/fipsmodule/rsa/rsa_impl.c b/crypto/fipsmodule/rsa/rsa_impl.c
index adbb69f..fb27320 100644
--- a/crypto/fipsmodule/rsa/rsa_impl.c
+++ b/crypto/fipsmodule/rsa/rsa_impl.c
@@ -775,19 +775,6 @@
};
const size_t kBoringSSLRSASqrtTwoLen = OPENSSL_ARRAY_SIZE(kBoringSSLRSASqrtTwo);
-int rsa_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
- OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
- crypto_word_t_too_small);
- int ret = 0;
- // Process the words in little-endian order.
- for (size_t i = 0; i < len; i++) {
- crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
- crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
- ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
- }
- return ret;
-}
-
int rsa_greater_than_pow2(const BIGNUM *b, int n) {
if (BN_is_negative(b) || n == INT_MAX) {
return 0;
@@ -866,7 +853,7 @@
if (to_check > out_len) {
to_check = out_len;
}
- if (!rsa_less_than_words(
+ if (!bn_less_than_words(
kBoringSSLRSASqrtTwo + kBoringSSLRSASqrtTwoLen - to_check,
out->d + out_len - to_check, to_check)) {
continue;
diff --git a/crypto/rsa_extra/rsa_test.cc b/crypto/rsa_extra/rsa_test.cc
index 23e8c67..97b32bf 100644
--- a/crypto/rsa_extra/rsa_test.cc
+++ b/crypto/rsa_extra/rsa_test.cc
@@ -735,58 +735,6 @@
EXPECT_EQ(3072u / 2u, bits);
}
-TEST(RSATest, LessThanWords) {
- // kTestVectors is an array of 256-bit values in sorted order.
- static const BN_ULONG kTestVectors[][256 / BN_BITS2] = {
- {TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
- TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
- {TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
- TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
- {TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000),
- TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
- {TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
- TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
- {TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
- TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000)},
- {TOBN(0x00000000, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0x00000000, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0xed17ac85, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0xed17ac85, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0xffffffff, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0xffffffff, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
- TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
- {TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
- TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff)},
- {TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
- TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
- {TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
- TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
- {TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff),
- TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
- {TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
- TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
- };
-
- for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) {
- SCOPED_TRACE(i);
- for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kTestVectors); j++) {
- SCOPED_TRACE(j);
- EXPECT_EQ(i < j ? 1 : 0,
- rsa_less_than_words(kTestVectors[i], kTestVectors[j],
- OPENSSL_ARRAY_SIZE(kTestVectors[i])));
- }
- }
-
- EXPECT_EQ(0, rsa_less_than_words(NULL, NULL, 0));
-}
-
TEST(RSATest, GreaterThanPow2) {
bssl::UniquePtr<BIGNUM> b(BN_new());
BN_zero(b.get());