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());