Rename bn->top to bn->width.

This has no behavior change, but it has a semantic one. This CL is an
assertion that all BIGNUM functions tolerate non-minimal BIGNUMs now.
Specifically:

- Functions that do not touch top/width are assumed to not care.

- Functions that do touch top/width will be changed by this CL. These
  should be checked in review that they tolerate non-minimal BIGNUMs.

Subsequent CLs will start adjusting the widths that BIGNUM functions
output, to fix timing leaks.

Bug: 232
Change-Id: I3a2b41b071f2174452f8d3801bce5c78947bb8f7
Reviewed-on: https://boringssl-review.googlesource.com/25257
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/bn_extra/convert.c b/crypto/bn_extra/convert.c
index b4a6014..c70ff8b 100644
--- a/crypto/bn_extra/convert.c
+++ b/crypto/bn_extra/convert.c
@@ -154,7 +154,7 @@
     in_len -= todo;
   }
   assert(i <= bn->dmax);
-  bn->top = i;
+  bn->width = i;
   return 1;
 }
 
@@ -223,7 +223,7 @@
     goto err;
   }
 
-  bn_correct_top(ret);
+  bn_set_minimal_width(ret);
   if (!BN_is_zero(ret)) {
     ret->neg = neg;
   }
diff --git a/crypto/fipsmodule/bn/add.c b/crypto/fipsmodule/bn/add.c
index 0c430ae..cc74510 100644
--- a/crypto/fipsmodule/bn/add.c
+++ b/crypto/fipsmodule/bn/add.c
@@ -105,20 +105,20 @@
   BN_ULONG *ap, *bp, *rp, carry, t1, t2;
   const BIGNUM *tmp;
 
-  if (a->top < b->top) {
+  if (a->width < b->width) {
     tmp = a;
     a = b;
     b = tmp;
   }
-  max = a->top;
-  min = b->top;
+  max = a->width;
+  min = b->width;
   dif = max - min;
 
   if (!bn_wexpand(r, max + 1)) {
     return 0;
   }
 
-  r->top = max;
+  r->width = max;
 
   ap = a->d;
   bp = b->d;
@@ -143,7 +143,7 @@
     if (carry) {
       // carry != 0 => dif == 0
       *rp = 1;
-      r->top++;
+      r->width++;
     }
   }
 
@@ -182,16 +182,16 @@
     return i;
   }
 
-  for (i = 0; w != 0 && i < a->top; i++) {
+  for (i = 0; w != 0 && i < a->width; i++) {
     a->d[i] = l = a->d[i] + w;
     w = (w > l) ? 1 : 0;
   }
 
-  if (w && i == a->top) {
-    if (!bn_wexpand(a, a->top + 1)) {
+  if (w && i == a->width) {
+    if (!bn_wexpand(a, a->width + 1)) {
       return 0;
     }
-    a->top++;
+    a->width++;
     a->d[i] = w;
   }
 
@@ -305,9 +305,9 @@
     OPENSSL_memcpy(rp, ap, sizeof(*rp) * dif);
   }
 
-  r->top = max;
+  r->width = max;
   r->neg = 0;
-  bn_correct_top(r);
+  bn_set_minimal_width(r);
 
   return 1;
 }
@@ -355,8 +355,8 @@
     }
   }
 
-  if ((a->d[i] == 0) && (i == (a->top - 1))) {
-    a->top--;
+  if ((a->d[i] == 0) && (i == (a->width - 1))) {
+    a->width--;
   }
 
   return 1;
diff --git a/crypto/fipsmodule/bn/bn.c b/crypto/fipsmodule/bn/bn.c
index 520ca27..b97bad7 100644
--- a/crypto/fipsmodule/bn/bn.c
+++ b/crypto/fipsmodule/bn/bn.c
@@ -148,13 +148,13 @@
     return dest;
   }
 
-  if (!bn_wexpand(dest, src->top)) {
+  if (!bn_wexpand(dest, src->width)) {
     return NULL;
   }
 
-  OPENSSL_memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top);
+  OPENSSL_memcpy(dest->d, src->d, sizeof(src->d[0]) * src->width);
 
-  dest->top = src->top;
+  dest->width = src->width;
   dest->neg = src->neg;
   return dest;
 }
@@ -164,14 +164,14 @@
     OPENSSL_memset(bn->d, 0, bn->dmax * sizeof(bn->d[0]));
   }
 
-  bn->top = 0;
+  bn->width = 0;
   bn->neg = 0;
 }
 
 DEFINE_METHOD_FUNCTION(BIGNUM, BN_value_one) {
   static const BN_ULONG kOneLimbs[1] = { 1 };
   out->d = (BN_ULONG*) kOneLimbs;
-  out->top = 1;
+  out->width = 1;
   out->dmax = 1;
   out->neg = 0;
   out->flags = BN_FLG_STATIC_DATA;
@@ -240,7 +240,7 @@
 }
 
 void BN_zero(BIGNUM *bn) {
-  bn->top = bn->neg = 0;
+  bn->width = bn->neg = 0;
 }
 
 int BN_one(BIGNUM *bn) {
@@ -259,7 +259,7 @@
 
   bn->neg = 0;
   bn->d[0] = value;
-  bn->top = 1;
+  bn->width = 1;
   return 1;
 }
 
@@ -278,7 +278,7 @@
   bn->neg = 0;
   bn->d[0] = (BN_ULONG)value;
   bn->d[1] = (BN_ULONG)(value >> 32);
-  bn->top = 2;
+  bn->width = 2;
   return 1;
 #else
 #error "BN_BITS2 must be 32 or 64."
@@ -291,8 +291,8 @@
   }
   OPENSSL_memmove(bn->d, words, num * sizeof(BN_ULONG));
   // |bn_wexpand| verified that |num| isn't too large.
-  bn->top = (int)num;
-  bn_correct_top(bn);
+  bn->width = (int)num;
+  bn_set_minimal_width(bn);
   bn->neg = 0;
   return 1;
 }
@@ -300,7 +300,7 @@
 int bn_fits_in_words(const BIGNUM *bn, size_t num) {
   // All words beyond |num| must be zero.
   BN_ULONG mask = 0;
-  for (size_t i = num; i < (size_t)bn->top; i++) {
+  for (size_t i = num; i < (size_t)bn->width; i++) {
     mask |= bn->d[i];
   }
   return mask == 0;
@@ -312,7 +312,7 @@
     return 0;
   }
 
-  size_t width = (size_t)bn->top;
+  size_t width = (size_t)bn->width;
   if (width > num) {
     if (!bn_fits_in_words(bn, num)) {
       OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
@@ -361,7 +361,7 @@
     return 0;
   }
 
-  OPENSSL_memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top);
+  OPENSSL_memcpy(a, bn->d, sizeof(BN_ULONG) * bn->width);
 
   OPENSSL_free(bn->d);
   bn->d = a;
@@ -379,12 +379,13 @@
 }
 
 int bn_resize_words(BIGNUM *bn, size_t words) {
-  if ((size_t)bn->top <= words) {
+  if ((size_t)bn->width <= words) {
     if (!bn_wexpand(bn, words)) {
       return 0;
     }
-    OPENSSL_memset(bn->d + bn->top, 0, (words - bn->top) * sizeof(BN_ULONG));
-    bn->top = words;
+    OPENSSL_memset(bn->d + bn->width, 0,
+                   (words - bn->width) * sizeof(BN_ULONG));
+    bn->width = words;
     return 1;
   }
 
@@ -393,21 +394,21 @@
     OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
     return 0;
   }
-  bn->top = words;
+  bn->width = words;
   return 1;
 }
 
 int bn_minimal_width(const BIGNUM *bn) {
-  int ret = bn->top;
+  int ret = bn->width;
   while (ret > 0 && bn->d[ret - 1] == 0) {
     ret--;
   }
   return ret;
 }
 
-void bn_correct_top(BIGNUM *bn) {
-  bn->top = bn_minimal_width(bn);
-  if (bn->top == 0) {
+void bn_set_minimal_width(BIGNUM *bn) {
+  bn->width = bn_minimal_width(bn);
+  if (bn->width == 0) {
     bn->neg = 0;
   }
 }
diff --git a/crypto/fipsmodule/bn/bn_test.cc b/crypto/fipsmodule/bn/bn_test.cc
index 757af27..a11d8c8 100644
--- a/crypto/fipsmodule/bn/bn_test.cc
+++ b/crypto/fipsmodule/bn/bn_test.cc
@@ -152,7 +152,7 @@
     if (resize) {
       // Test with an oversized |BIGNUM| if necessary.
       if ((large_mask_ & (1 << num_bignums_)) &&
-          !bn_resize_words(ret.get(), ret->top * 2 + 1)) {
+          !bn_resize_words(ret.get(), ret->width * 2 + 1)) {
         return nullptr;
       }
       num_bignums_++;
@@ -726,7 +726,7 @@
       ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m_width, a_words.get(),
                                          m_width, mont.get()));
       ASSERT_TRUE(bn_mod_exp_mont_small(r_words.get(), m_width, a_words.get(),
-                                        m_width, e->d, e->top, mont.get()));
+                                        m_width, e->d, e->width, mont.get()));
       ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m_width,
                                            r_words.get(), m_width, mont.get()));
       ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m_width));
@@ -1975,9 +1975,9 @@
     SCOPED_TRACE(width);
     // Make |ten| and |zero| wider.
     EXPECT_TRUE(bn_resize_words(ten.get(), width));
-    EXPECT_EQ(static_cast<int>(width), ten->top);
+    EXPECT_EQ(static_cast<int>(width), ten->width);
     EXPECT_TRUE(bn_resize_words(zero.get(), width));
-    EXPECT_EQ(static_cast<int>(width), zero->top);
+    EXPECT_EQ(static_cast<int>(width), zero->width);
 
     EXPECT_TRUE(BN_abs_is_word(ten.get(), 10));
     EXPECT_TRUE(BN_is_word(ten.get(), 10));
@@ -2036,14 +2036,14 @@
 
   // |ten| may be resized back down to one word.
   EXPECT_TRUE(bn_resize_words(ten.get(), 1));
-  EXPECT_EQ(1, ten->top);
+  EXPECT_EQ(1, ten->width);
 
   // But not to zero words, which it does not fit.
   EXPECT_FALSE(bn_resize_words(ten.get(), 0));
 
   EXPECT_TRUE(BN_is_pow2(eight.get()));
   EXPECT_TRUE(bn_resize_words(eight.get(), 4));
-  EXPECT_EQ(4, eight->top);
+  EXPECT_EQ(4, eight->width);
   EXPECT_TRUE(BN_is_pow2(eight.get()));
 
   // |BN_MONT_CTX| is always stored minimally and uses the same R independent of
@@ -2065,6 +2065,6 @@
       BN_MONT_CTX_new_for_modulus(p.get(), ctx()));
   ASSERT_TRUE(mont2);
 
-  EXPECT_EQ(mont->N.top, mont2->N.top);
+  EXPECT_EQ(mont->N.width, mont2->N.width);
   EXPECT_EQ(0, BN_cmp(&mont->RR, &mont2->RR));
 }
diff --git a/crypto/fipsmodule/bn/bytes.c b/crypto/fipsmodule/bn/bytes.c
index aa65483..091def0 100644
--- a/crypto/fipsmodule/bn/bytes.c
+++ b/crypto/fipsmodule/bn/bytes.c
@@ -77,7 +77,7 @@
   }
 
   if (len == 0) {
-    ret->top = 0;
+    ret->width = 0;
     return ret;
   }
 
@@ -93,7 +93,7 @@
   // |bn_wexpand| must check bounds on |num_words| to write it into
   // |ret->dmax|.
   assert(num_words <= INT_MAX);
-  ret->top = (int)num_words;
+  ret->width = (int)num_words;
   ret->neg = 0;
 
   while (len--) {
@@ -107,7 +107,7 @@
 
   // need to call this due to clear byte at top if avoiding having the top bit
   // set (-ve number)
-  bn_correct_top(ret);
+  bn_set_minimal_width(ret);
   return ret;
 }
 
@@ -123,7 +123,7 @@
   }
 
   if (len == 0) {
-    ret->top = 0;
+    ret->width = 0;
     ret->neg = 0;
     return ret;
   }
@@ -134,7 +134,7 @@
     BN_free(bn);
     return NULL;
   }
-  ret->top = num_words;
+  ret->width = num_words;
 
   // Make sure the top bytes will be zeroed.
   ret->d[num_words - 1] = 0;
@@ -143,7 +143,7 @@
   // internal representation.
   OPENSSL_memcpy(ret->d, in, len);
 
-  bn_correct_top(ret);
+  bn_set_minimal_width(ret);
   return ret;
 }
 
@@ -161,7 +161,8 @@
 
 // TODO(davidben): This does not need to be quite so complex once the |BIGNUM|s
 // we care about are fixed-width. |read_word_padded| is a hack to paper over
-// parts of the |bn_correct_top| leak. Fix that, and this can be simpler.
+// the historical |bn_minimal_width| leak. This can be simplified once that's
+// fixed.
 
 // constant_time_select_ulong returns |x| if |v| is 1 and |y| if |v| is 0. Its
 // behavior is undefined if |v| takes any other value.
@@ -192,13 +193,15 @@
   BN_ULONG l = in->d[constant_time_select_ulong(
       constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)];
 
-  // Clamp to zero if above |d->top|.
-  return constant_time_select_ulong(constant_time_le_size_t(in->top, i), 0, l);
+  // Clamp to zero if above |d->width|.
+  return constant_time_select_ulong(constant_time_le_size_t(in->width, i), 0,
+                                    l);
 }
 
 static int fits_in_bytes(const BIGNUM *in, size_t len) {
   BN_ULONG mask = 0;
-  for (size_t i = (len + (BN_BYTES - 1)) / BN_BYTES; i < (size_t)in->top; i++) {
+  for (size_t i = (len + (BN_BYTES - 1)) / BN_BYTES; i < (size_t)in->width;
+       i++) {
     mask |= in->d[i];
   }
   if ((len % BN_BYTES) != 0) {
@@ -214,7 +217,7 @@
     return 0;
   }
 
-  size_t todo = in->top * BN_BYTES;
+  size_t todo = in->width * BN_BYTES;
   if (todo > len) {
     todo = len;
   }
@@ -237,7 +240,7 @@
   }
 
   // Write the bytes out one by one. Serialization is done without branching on
-  // the bits of |in| or on |in->top|, but if the routine would otherwise read
+  // the bits of |in| or on |in->width|, but if the routine would otherwise read
   // out of bounds, the memory access pattern can't be fixed. However, for an
   // RSA key of size a multiple of the word size, the probability of BN_BYTES
   // leading zero octets is low.
diff --git a/crypto/fipsmodule/bn/cmp.c b/crypto/fipsmodule/bn/cmp.c
index 265c852..f5b4fdc 100644
--- a/crypto/fipsmodule/bn/cmp.c
+++ b/crypto/fipsmodule/bn/cmp.c
@@ -228,7 +228,7 @@
   BN_init(&b_bn);
 
   b_bn.d = &b;
-  b_bn.top = b > 0;
+  b_bn.width = b > 0;
   b_bn.dmax = 1;
   b_bn.flags = BN_FLG_STATIC_DATA;
   return BN_cmp(a, &b_bn);
@@ -247,7 +247,7 @@
 }
 
 int BN_is_odd(const BIGNUM *bn) {
-  return bn->top > 0 && (bn->d[0] & 1) == 1;
+  return bn->width > 0 && (bn->d[0] & 1) == 1;
 }
 
 int BN_is_pow2(const BIGNUM *bn) {
@@ -268,14 +268,14 @@
 int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) {
   BN_ULONG mask = 0;
   // If |a| or |b| has more words than the other, all those words must be zero.
-  for (int i = a->top; i < b->top; i++) {
+  for (int i = a->width; i < b->width; i++) {
     mask |= b->d[i];
   }
-  for (int i = b->top; i < a->top; i++) {
+  for (int i = b->width; i < a->width; i++) {
     mask |= a->d[i];
   }
   // Common words must match.
-  int min = a->top < b->top ? a->top : b->top;
+  int min = a->width < b->width ? a->width : b->width;
   for (int i = 0; i < min; i++) {
     mask |= (a->d[i] ^ b->d[i]);
   }
@@ -298,5 +298,5 @@
     a = b;
     b = tmp;
   }
-  return bn_less_than_words_impl(a->d, a->top, b->d, b->top);
+  return bn_less_than_words_impl(a->d, a->width, b->d, b->width);
 }
diff --git a/crypto/fipsmodule/bn/div.c b/crypto/fipsmodule/bn/div.c
index be8c582..453bd0f 100644
--- a/crypto/fipsmodule/bn/div.c
+++ b/crypto/fipsmodule/bn/div.c
@@ -240,48 +240,48 @@
   if (!BN_lshift(sdiv, divisor, norm_shift)) {
     goto err;
   }
-  bn_correct_top(sdiv);
+  bn_set_minimal_width(sdiv);
   sdiv->neg = 0;
   norm_shift += BN_BITS2;
   if (!BN_lshift(snum, numerator, norm_shift)) {
     goto err;
   }
-  bn_correct_top(snum);
+  bn_set_minimal_width(snum);
   snum->neg = 0;
 
   // Since we don't want to have special-case logic for the case where snum is
   // larger than sdiv, we pad snum with enough zeroes without changing its
   // value.
-  if (snum->top <= sdiv->top + 1) {
-    if (!bn_wexpand(snum, sdiv->top + 2)) {
+  if (snum->width <= sdiv->width + 1) {
+    if (!bn_wexpand(snum, sdiv->width + 2)) {
       goto err;
     }
-    for (int i = snum->top; i < sdiv->top + 2; i++) {
+    for (int i = snum->width; i < sdiv->width + 2; i++) {
       snum->d[i] = 0;
     }
-    snum->top = sdiv->top + 2;
+    snum->width = sdiv->width + 2;
   } else {
-    if (!bn_wexpand(snum, snum->top + 1)) {
+    if (!bn_wexpand(snum, snum->width + 1)) {
       goto err;
     }
-    snum->d[snum->top] = 0;
-    snum->top++;
+    snum->d[snum->width] = 0;
+    snum->width++;
   }
 
-  div_n = sdiv->top;
-  num_n = snum->top;
+  div_n = sdiv->width;
+  num_n = snum->width;
   loop = num_n - div_n;
   // Lets setup a 'window' into snum
   // This is the part that corresponds to the current
   // 'area' being divided
   wnum.neg = 0;
   wnum.d = &(snum->d[loop]);
-  wnum.top = div_n;
-  // only needed when BN_ucmp messes up the values between top and max
+  wnum.width = div_n;
+  // only needed when BN_ucmp messes up the values between width and max
   wnum.dmax = snum->dmax - loop;  // so we don't step out of bounds
 
   // Get the top 2 words of sdiv
-  // div_n=sdiv->top;
+  // div_n=sdiv->width;
   d0 = sdiv->d[div_n - 1];
   d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];
 
@@ -293,7 +293,7 @@
   if (!bn_wexpand(res, loop + 1)) {
     goto err;
   }
-  res->top = loop - 1;
+  res->width = loop - 1;
   resp = &(res->d[loop - 1]);
 
   // space for temp
@@ -301,9 +301,9 @@
     goto err;
   }
 
-  // if res->top == 0 then clear the neg value otherwise decrease
+  // if res->width == 0 then clear the neg value otherwise decrease
   // the resp pointer
-  if (res->top == 0) {
+  if (res->width == 0) {
     res->neg = 0;
   } else {
     resp--;
@@ -379,7 +379,7 @@
     *resp = q;
   }
 
-  bn_correct_top(snum);
+  bn_set_minimal_width(snum);
 
   if (rem != NULL) {
     // Keep a copy of the neg flag in numerator because if |rem| == |numerator|
@@ -393,7 +393,7 @@
     }
   }
 
-  bn_correct_top(res);
+  bn_set_minimal_width(res);
   BN_CTX_end(ctx);
   return 1;
 
@@ -592,7 +592,7 @@
     return (BN_ULONG) - 1;
   }
 
-  if (a->top == 0) {
+  if (a->width == 0) {
     return 0;
   }
 
@@ -603,7 +603,7 @@
     return (BN_ULONG) - 1;
   }
 
-  for (i = a->top - 1; i >= 0; i--) {
+  for (i = a->width - 1; i >= 0; i--) {
     BN_ULONG l = a->d[i];
     BN_ULONG d;
     BN_ULONG unused_rem;
@@ -612,7 +612,7 @@
     a->d[i] = d;
   }
 
-  bn_correct_top(a);
+  bn_set_minimal_width(a);
   ret >>= j;
   return ret;
 }
@@ -643,7 +643,7 @@
   }
 #endif
 
-  for (i = a->top - 1; i >= 0; i--) {
+  for (i = a->width - 1; i >= 0; i--) {
 #ifndef BN_CAN_DIVIDE_ULLONG
     ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
     ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w;
@@ -655,7 +655,7 @@
 }
 
 int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
-  if (e == 0 || a->top == 0) {
+  if (e == 0 || a->width == 0) {
     BN_zero(r);
     return 1;
   }
@@ -663,7 +663,7 @@
   size_t num_words = 1 + ((e - 1) / BN_BITS2);
 
   // If |a| definitely has less than |e| bits, just BN_copy.
-  if ((size_t) a->top < num_words) {
+  if ((size_t) a->width < num_words) {
     return BN_copy(r, a) != NULL;
   }
 
@@ -684,8 +684,8 @@
 
   // Fill in the remaining fields of |r|.
   r->neg = a->neg;
-  r->top = (int) num_words;
-  bn_correct_top(r);
+  r->width = (int) num_words;
+  bn_set_minimal_width(r);
   return 1;
 }
 
@@ -707,27 +707,27 @@
   }
 
   // Clear the upper words of |r|.
-  OPENSSL_memset(&r->d[r->top], 0, (num_words - r->top) * BN_BYTES);
+  OPENSSL_memset(&r->d[r->width], 0, (num_words - r->width) * BN_BYTES);
 
   // Set parameters of |r|.
   r->neg = 0;
-  r->top = (int) num_words;
+  r->width = (int) num_words;
 
   // Now, invert every word. The idea here is that we want to compute 2^e-|x|,
   // which is actually equivalent to the twos-complement representation of |x|
   // in |e| bits, which is -x = ~x + 1.
-  for (int i = 0; i < r->top; i++) {
+  for (int i = 0; i < r->width; i++) {
     r->d[i] = ~r->d[i];
   }
 
   // If our exponent doesn't span the top word, we have to mask the rest.
   size_t top_word_exponent = e % BN_BITS2;
   if (top_word_exponent != 0) {
-    r->d[r->top - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
+    r->d[r->width - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
   }
 
-  // Keep the correct_top invariant for BN_add.
-  bn_correct_top(r);
+  // Keep the minimal-width invariant for |BIGNUM|.
+  bn_set_minimal_width(r);
 
   // Finally, add one, for the reason described above.
   return BN_add(r, r, BN_value_one());
diff --git a/crypto/fipsmodule/bn/exponentiation.c b/crypto/fipsmodule/bn/exponentiation.c
index b62292d..f3cc57f 100644
--- a/crypto/fipsmodule/bn/exponentiation.c
+++ b/crypto/fipsmodule/bn/exponentiation.c
@@ -731,7 +731,7 @@
 int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
                           size_t num_a, const BN_ULONG *p, size_t num_p,
                           const BN_MONT_CTX *mont) {
-  size_t num_n = mont->N.top;
+  size_t num_n = mont->N.width;
   if (num_n != num_a || num_n != num_r || num_n > BN_SMALL_MAX_WORDS) {
     OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
@@ -841,7 +841,7 @@
                                     const BN_ULONG *a, size_t num_a,
                                     const BN_MONT_CTX *mont) {
   const BN_ULONG *p = mont->N.d;
-  size_t num_p = mont->N.top;
+  size_t num_p = mont->N.width;
   if (num_p > BN_SMALL_MAX_WORDS || num_p == 0) {
     OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
@@ -876,8 +876,8 @@
   const int width = 1 << window;
   BN_ULONG *table = (BN_ULONG *) buf;
 
-  if (top > b->top) {
-    top = b->top;  // this works because 'buf' is explicitly zeroed
+  if (top > b->width) {
+    top = b->width;  // this works because 'buf' is explicitly zeroed
   }
 
   for (i = 0, j = idx; i < top; i++, j += width)  {
@@ -930,8 +930,8 @@
     }
   }
 
-  b->top = top;
-  bn_correct_top(b);
+  b->width = top;
+  bn_set_minimal_width(b);
   return 1;
 }
 
@@ -998,7 +998,7 @@
 
   // Use all bits stored in |p|, rather than |BN_num_bits|, so we do not leak
   // whether the top bits are zero.
-  int max_bits = p->top * BN_BITS2;
+  int max_bits = p->width * BN_BITS2;
   int bits = max_bits;
   if (bits == 0) {
     // x**0 mod 1 is still zero.
@@ -1020,7 +1020,7 @@
 
   // Use the width in |mont->N|, rather than the copy in |m|. The assembly
   // implementation assumes it can use |top| to size R.
-  int top = mont->N.top;
+  int top = mont->N.width;
 
   if (a->neg || BN_ucmp(a, m) >= 0) {
     new_a = BN_new();
@@ -1035,15 +1035,15 @@
   // If the size of the operands allow it, perform the optimized
   // RSAZ exponentiation. For further information see
   // crypto/bn/rsaz_exp.c and accompanying assembly modules.
-  if ((16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024) &&
+  if ((16 == a->width) && (16 == p->width) && (BN_num_bits(m) == 1024) &&
       rsaz_avx2_eligible()) {
     if (!bn_wexpand(rr, 16)) {
       goto err;
     }
     RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d, mont->n0[0]);
-    rr->top = 16;
+    rr->width = 16;
     rr->neg = 0;
-    bn_correct_top(rr);
+    bn_set_minimal_width(rr);
     ret = 1;
     goto err;
   }
@@ -1089,7 +1089,7 @@
   // lay down tmp and am right after powers table
   tmp.d = (BN_ULONG *)(powerbuf + sizeof(m->d[0]) * top * numPowers);
   am.d = tmp.d + top;
-  tmp.top = am.top = 0;
+  tmp.width = am.width = 0;
   tmp.dmax = am.dmax = top;
   tmp.neg = am.neg = 0;
   tmp.flags = am.flags = BN_FLG_STATIC_DATA;
@@ -1118,10 +1118,10 @@
 
     // BN_to_montgomery can contaminate words above .top
     // [in BN_DEBUG[_DEBUG] build]...
-    for (i = am.top; i < top; i++) {
+    for (i = am.width; i < top; i++) {
       am.d[i] = 0;
     }
-    for (i = tmp.top; i < top; i++) {
+    for (i = tmp.width; i < top; i++) {
       tmp.d[i] = 0;
     }
 
@@ -1131,7 +1131,7 @@
     }
 
     bn_scatter5(tmp.d, top, powerbuf, 0);
-    bn_scatter5(am.d, am.top, powerbuf, 1);
+    bn_scatter5(am.d, am.width, powerbuf, 1);
     bn_mul_mont(tmp.d, am.d, am.d, np, n0, top);
     bn_scatter5(tmp.d, top, powerbuf, 2);
 
@@ -1198,7 +1198,7 @@
       // here is the top bit, inclusive.
       if (bits - 4 >= max_bits - 8) {
         // Read five bits from |bits-4| through |bits|, inclusive.
-        wvalue = p_bytes[p->top * BN_BYTES - 1];
+        wvalue = p_bytes[p->width * BN_BYTES - 1];
         wvalue >>= (bits - 4) & 7;
         wvalue &= 0x1f;
         bits -= 5;
@@ -1217,8 +1217,8 @@
     }
 
     ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np, n0, top);
-    tmp.top = top;
-    bn_correct_top(&tmp);
+    tmp.width = top;
+    bn_set_minimal_width(&tmp);
     if (ret) {
       if (!BN_copy(rr, &tmp)) {
         ret = 0;
diff --git a/crypto/fipsmodule/bn/internal.h b/crypto/fipsmodule/bn/internal.h
index 2fec60c..17c9cd3 100644
--- a/crypto/fipsmodule/bn/internal.h
+++ b/crypto/fipsmodule/bn/internal.h
@@ -201,9 +201,9 @@
 // value of |bn|.
 int bn_minimal_width(const BIGNUM *bn);
 
-// bn_correct_top decrements |bn->top| to |bn_minimal_width|. If |bn| is zero,
-// |bn->neg| is set to zero.
-void bn_correct_top(BIGNUM *bn);
+// bn_set_minimal_width sets |bn->width| to |bn_minimal_width(bn)|. If |bn| is
+// zero, |bn->neg| is set to zero.
+void bn_set_minimal_width(BIGNUM *bn);
 
 // bn_wexpand ensures that |bn| has at least |words| works of space without
 // altering its value. It returns one on success or zero on allocation
@@ -216,10 +216,6 @@
 
 // bn_resize_words adjusts |bn->top| to be |words|. It returns one on success
 // and zero on allocation error or if |bn|'s value is too large.
-//
-// Do not call this function outside of unit tests. Most functions currently
-// require |BIGNUM|s be minimal. This function breaks that invariant. It is
-// introduced early so the invariant may be relaxed incrementally.
 OPENSSL_EXPORT int bn_resize_words(BIGNUM *bn, size_t words);
 
 // bn_set_words sets |bn| to the value encoded in the |num| words in |words|,
diff --git a/crypto/fipsmodule/bn/jacobi.c b/crypto/fipsmodule/bn/jacobi.c
index 9c909bb..d1a9d50 100644
--- a/crypto/fipsmodule/bn/jacobi.c
+++ b/crypto/fipsmodule/bn/jacobi.c
@@ -58,7 +58,7 @@
 
 
 // least significant word
-#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
+#define BN_lsw(n) (((n)->width == 0) ? (BN_ULONG) 0 : (n)->d[0])
 
 int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
   // In 'tab', only odd-indexed entries are relevant:
diff --git a/crypto/fipsmodule/bn/montgomery.c b/crypto/fipsmodule/bn/montgomery.c
index a51725c..baa9a0e 100644
--- a/crypto/fipsmodule/bn/montgomery.c
+++ b/crypto/fipsmodule/bn/montgomery.c
@@ -192,7 +192,7 @@
   // |mont->N| is always stored minimally. Computing RR efficiently leaks the
   // size of the modulus. While the modulus may be private in RSA (one of the
   // primes), their sizes are public, so this is fine.
-  bn_correct_top(&mont->N);
+  bn_set_minimal_width(&mont->N);
 
   // Find n0 such that n0 * N == -1 (mod r).
   //
@@ -215,7 +215,7 @@
   // as |BN_MONT_CTX_N0_LIMBS| is either one or two.
   //
   // XXX: This is not constant time with respect to |mont->N|, but it should be.
-  unsigned lgBigR = mont->N.top * BN_BITS2;
+  unsigned lgBigR = mont->N.width * BN_BITS2;
   if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) {
     return 0;
   }
@@ -260,7 +260,7 @@
 static int bn_from_montgomery_in_place(BN_ULONG *r, size_t num_r, BN_ULONG *a,
                                        size_t num_a, const BN_MONT_CTX *mont) {
   const BN_ULONG *n = mont->N.d;
-  size_t num_n = mont->N.top;
+  size_t num_n = mont->N.width;
   if (num_r != num_n || num_a != 2 * num_n) {
     OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
@@ -307,25 +307,25 @@
   }
 
   const BIGNUM *n = &mont->N;
-  if (n->top == 0) {
-    ret->top = 0;
+  if (n->width == 0) {
+    ret->width = 0;
     return 1;
   }
 
-  int max = (2 * n->top);  // carry is stored separately
+  int max = (2 * n->width);  // carry is stored separately
   if (!bn_resize_words(r, max) ||
-      !bn_wexpand(ret, n->top)) {
+      !bn_wexpand(ret, n->width)) {
     return 0;
   }
-  ret->top = n->top;
+  ret->width = n->width;
 
-  if (!bn_from_montgomery_in_place(ret->d, ret->top, r->d, r->top, mont)) {
+  if (!bn_from_montgomery_in_place(ret->d, ret->width, r->d, r->width, mont)) {
     return 0;
   }
   ret->neg = 0;
 
-  bn_correct_top(r);
-  bn_correct_top(ret);
+  bn_set_minimal_width(r);
+  bn_set_minimal_width(ret);
   return 1;
 }
 
@@ -350,22 +350,22 @@
 }
 
 int bn_one_to_montgomery(BIGNUM *r, const BN_MONT_CTX *mont, BN_CTX *ctx) {
-  // If the high bit of |n| is set, R = 2^(top*BN_BITS2) < 2 * |n|, so we
+  // If the high bit of |n| is set, R = 2^(width*BN_BITS2) < 2 * |n|, so we
   // compute R - |n| rather than perform Montgomery reduction.
   const BIGNUM *n = &mont->N;
-  if (n->top > 0 && (n->d[n->top - 1] >> (BN_BITS2 - 1)) != 0) {
-    if (!bn_wexpand(r, n->top)) {
+  if (n->width > 0 && (n->d[n->width - 1] >> (BN_BITS2 - 1)) != 0) {
+    if (!bn_wexpand(r, n->width)) {
       return 0;
     }
     r->d[0] = 0 - n->d[0];
-    for (int i = 1; i < n->top; i++) {
+    for (int i = 1; i < n->width; i++) {
       r->d[i] = ~n->d[i];
     }
-    r->top = n->top;
+    r->width = n->width;
     r->neg = 0;
     // The upper words will be zero if the corresponding words of |n| were
-    // 0xfff[...], so call |bn_correct_top|.
-    bn_correct_top(r);
+    // 0xfff[...], so call |bn_set_minimal_width|.
+    bn_set_minimal_width(r);
     return 1;
   }
 
@@ -415,10 +415,10 @@
 
 #if defined(OPENSSL_BN_ASM_MONT)
   // |bn_mul_mont| requires at least 128 bits of limbs, at least for x86.
-  int num = mont->N.top;
+  int num = mont->N.width;
   if (num >= (128 / BN_BITS2) &&
-      a->top == num &&
-      b->top == num) {
+      a->width == num &&
+      b->width == num) {
     if (!bn_wexpand(r, num)) {
       return 0;
     }
@@ -429,8 +429,8 @@
       return 0;
     }
     r->neg = 0;
-    r->top = num;
-    bn_correct_top(r);
+    r->width = num;
+    bn_set_minimal_width(r);
 
     return 1;
   }
@@ -441,18 +441,18 @@
 
 int bn_less_than_montgomery_R(const BIGNUM *bn, const BN_MONT_CTX *mont) {
   return !BN_is_negative(bn) &&
-         bn_fits_in_words(bn, mont->N.top);
+         bn_fits_in_words(bn, mont->N.width);
 }
 
 int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
                            size_t num_a, const BN_MONT_CTX *mont) {
   return bn_mod_mul_montgomery_small(r, num_r, a, num_a, mont->RR.d,
-                                     mont->RR.top, mont);
+                                     mont->RR.width, mont);
 }
 
 int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
                              size_t num_a, const BN_MONT_CTX *mont) {
-  size_t num_n = mont->N.top;
+  size_t num_n = mont->N.width;
   if (num_a > 2 * num_n || num_r != num_n || num_n > BN_SMALL_MAX_WORDS) {
     OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
@@ -469,7 +469,7 @@
 int bn_one_to_montgomery_small(BN_ULONG *r, size_t num_r,
                                const BN_MONT_CTX *mont) {
   const BN_ULONG *n = mont->N.d;
-  size_t num_n = mont->N.top;
+  size_t num_n = mont->N.width;
   if (num_n == 0 || num_r != num_n) {
     OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
@@ -485,13 +485,13 @@
     return 1;
   }
 
-  return bn_from_montgomery_small(r, num_r, mont->RR.d, mont->RR.top, mont);
+  return bn_from_montgomery_small(r, num_r, mont->RR.d, mont->RR.width, mont);
 }
 
 int bn_mod_mul_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
                                 size_t num_a, const BN_ULONG *b, size_t num_b,
                                 const BN_MONT_CTX *mont) {
-  size_t num_n = mont->N.top;
+  size_t num_n = mont->N.width;
   if (num_r != num_n || num_a + num_b > 2 * num_n ||
       num_n > BN_SMALL_MAX_WORDS) {
     OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
diff --git a/crypto/fipsmodule/bn/montgomery_inv.c b/crypto/fipsmodule/bn/montgomery_inv.c
index c3c788a..f21d045 100644
--- a/crypto/fipsmodule/bn/montgomery_inv.c
+++ b/crypto/fipsmodule/bn/montgomery_inv.c
@@ -71,7 +71,7 @@
   // |BN_MONT_CTX_N0_LIMBS| limbs of |n|.
   uint64_t n_mod_r = n->d[0];
 #if BN_MONT_CTX_N0_LIMBS == 2
-  if (n->top > 1) {
+  if (n->width > 1) {
     n_mod_r |= (uint64_t)n->d[1] << BN_BITS2;
   }
 #endif
diff --git a/crypto/fipsmodule/bn/mul.c b/crypto/fipsmodule/bn/mul.c
index 3303478..dad962e 100644
--- a/crypto/fipsmodule/bn/mul.c
+++ b/crypto/fipsmodule/bn/mul.c
@@ -567,8 +567,8 @@
   BIGNUM *t = NULL;
   int j = 0, k;
 
-  al = a->top;
-  bl = b->top;
+  al = a->width;
+  bl = b->width;
 
   if ((al == 0) || (bl == 0)) {
     BN_zero(r);
@@ -592,7 +592,7 @@
       if (!bn_wexpand(rr, 16)) {
         goto err;
       }
-      rr->top = 16;
+      rr->width = 16;
       bn_mul_comba8(rr->d, a->d, b->d);
       goto end;
     }
@@ -634,7 +634,7 @@
         }
         bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
       }
-      rr->top = top;
+      rr->width = top;
       goto end;
     }
   }
@@ -642,11 +642,11 @@
   if (!bn_wexpand(rr, top)) {
     goto err;
   }
-  rr->top = top;
+  rr->width = top;
   bn_mul_normal(rr->d, a->d, al, b->d, bl);
 
 end:
-  bn_correct_top(rr);
+  bn_set_minimal_width(rr);
   if (r != rr && !BN_copy(r, rr)) {
     goto err;
   }
@@ -793,7 +793,7 @@
 }
 
 int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
-  if (!bn->top) {
+  if (!bn->width) {
     return 1;
   }
 
@@ -802,12 +802,12 @@
     return 1;
   }
 
-  BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->top, w);
+  BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->width, w);
   if (ll) {
-    if (!bn_wexpand(bn, bn->top + 1)) {
+    if (!bn_wexpand(bn, bn->width + 1)) {
       return 0;
     }
-    bn->d[bn->top++] = ll;
+    bn->d[bn->width++] = ll;
   }
 
   return 1;
@@ -818,9 +818,9 @@
   int ret = 0;
   BIGNUM *tmp, *rr;
 
-  al = a->top;
+  al = a->width;
   if (al <= 0) {
-    r->top = 0;
+    r->width = 0;
     r->neg = 0;
     return 1;
   }
@@ -866,8 +866,8 @@
   }
 
   rr->neg = 0;
-  rr->top = max;
-  bn_correct_top(rr);
+  rr->width = max;
+  bn_set_minimal_width(rr);
 
   if (rr != r && !BN_copy(r, rr)) {
     goto err;
diff --git a/crypto/fipsmodule/bn/random.c b/crypto/fipsmodule/bn/random.c
index 61499af..134afe0 100644
--- a/crypto/fipsmodule/bn/random.c
+++ b/crypto/fipsmodule/bn/random.c
@@ -278,15 +278,15 @@
 
 int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
                      const BIGNUM *max_exclusive) {
-  if (!bn_wexpand(r, max_exclusive->top) ||
+  if (!bn_wexpand(r, max_exclusive->width) ||
       !bn_rand_range_words(r->d, min_inclusive, max_exclusive->d,
-                           max_exclusive->top, kDefaultAdditionalData)) {
+                           max_exclusive->width, kDefaultAdditionalData)) {
     return 0;
   }
 
   r->neg = 0;
-  r->top = max_exclusive->top;
-  bn_correct_top(r);
+  r->width = max_exclusive->width;
+  bn_set_minimal_width(r);
   return 1;
 }
 
diff --git a/crypto/fipsmodule/bn/shift.c b/crypto/fipsmodule/bn/shift.c
index bedab09..0fda855 100644
--- a/crypto/fipsmodule/bn/shift.c
+++ b/crypto/fipsmodule/bn/shift.c
@@ -75,28 +75,28 @@
 
   r->neg = a->neg;
   nw = n / BN_BITS2;
-  if (!bn_wexpand(r, a->top + nw + 1)) {
+  if (!bn_wexpand(r, a->width + nw + 1)) {
     return 0;
   }
   lb = n % BN_BITS2;
   rb = BN_BITS2 - lb;
   f = a->d;
   t = r->d;
-  t[a->top + nw] = 0;
+  t[a->width + nw] = 0;
   if (lb == 0) {
-    for (i = a->top - 1; i >= 0; i--) {
+    for (i = a->width - 1; i >= 0; i--) {
       t[nw + i] = f[i];
     }
   } else {
-    for (i = a->top - 1; i >= 0; i--) {
+    for (i = a->width - 1; i >= 0; i--) {
       l = f[i];
       t[nw + i + 1] |= l >> rb;
       t[nw + i] = l << lb;
     }
   }
   OPENSSL_memset(t, 0, nw * sizeof(t[0]));
-  r->top = a->top + nw + 1;
-  bn_correct_top(r);
+  r->width = a->width + nw + 1;
+  bn_set_minimal_width(r);
 
   return 1;
 }
@@ -107,26 +107,26 @@
 
   if (r != a) {
     r->neg = a->neg;
-    if (!bn_wexpand(r, a->top + 1)) {
+    if (!bn_wexpand(r, a->width + 1)) {
       return 0;
     }
-    r->top = a->top;
+    r->width = a->width;
   } else {
-    if (!bn_wexpand(r, a->top + 1)) {
+    if (!bn_wexpand(r, a->width + 1)) {
       return 0;
     }
   }
   ap = a->d;
   rp = r->d;
   c = 0;
-  for (i = 0; i < a->top; i++) {
+  for (i = 0; i < a->width; i++) {
     t = *(ap++);
     *(rp++) = (t << 1) | c;
     c = t >> (BN_BITS2 - 1);
   }
   if (c) {
     *rp = 1;
-    r->top++;
+    r->width++;
   }
 
   return 1;
@@ -165,7 +165,7 @@
   f = &(a->d[nw]);
   t = r->d;
   j = a_width - nw;
-  r->top = i;
+  r->width = i;
 
   if (rb == 0) {
     for (i = j; i != 0; i--) {
@@ -184,7 +184,7 @@
     }
   }
 
-  if (r->top == 0) {
+  if (r->width == 0) {
     r->neg = 0;
   }
 
@@ -219,9 +219,9 @@
     rp[i] = (t >> 1) | c;
     c = t << (BN_BITS2 - 1);
   }
-  r->top = j;
+  r->width = j;
 
-  if (r->top == 0) {
+  if (r->width == 0) {
     r->neg = 0;
   }
 
@@ -235,14 +235,14 @@
 
   int i = n / BN_BITS2;
   int j = n % BN_BITS2;
-  if (a->top <= i) {
+  if (a->width <= i) {
     if (!bn_wexpand(a, i + 1)) {
       return 0;
     }
-    for (int k = a->top; k < i + 1; k++) {
+    for (int k = a->width; k < i + 1; k++) {
       a->d[k] = 0;
     }
-    a->top = i + 1;
+    a->width = i + 1;
   }
 
   a->d[i] |= (((BN_ULONG)1) << j);
@@ -259,12 +259,12 @@
 
   i = n / BN_BITS2;
   j = n % BN_BITS2;
-  if (a->top <= i) {
+  if (a->width <= i) {
     return 0;
   }
 
   a->d[i] &= (~(((BN_ULONG)1) << j));
-  bn_correct_top(a);
+  bn_set_minimal_width(a);
   return 1;
 }
 
@@ -281,7 +281,7 @@
   if (n < 0) {
     return 0;
   }
-  return bn_is_bit_set_words(a->d, a->top, n);
+  return bn_is_bit_set_words(a->d, a->width, n);
 }
 
 int BN_mask_bits(BIGNUM *a, int n) {
@@ -291,16 +291,16 @@
 
   int w = n / BN_BITS2;
   int b = n % BN_BITS2;
-  if (w >= a->top) {
+  if (w >= a->width) {
     return 0;
   }
   if (b == 0) {
-    a->top = w;
+    a->width = w;
   } else {
-    a->top = w + 1;
+    a->width = w + 1;
     a->d[w] &= ~(BN_MASK2 << b);
   }
 
-  bn_correct_top(a);
+  bn_set_minimal_width(a);
   return 1;
 }
diff --git a/crypto/fipsmodule/ec/ec.c b/crypto/fipsmodule/ec/ec.c
index cc1e633..215acbb 100644
--- a/crypto/fipsmodule/ec/ec.c
+++ b/crypto/fipsmodule/ec/ec.c
@@ -388,7 +388,7 @@
     return 0;
   }
   // Store the order in minimal form, so it can be used with |BN_ULONG| arrays.
-  bn_correct_top(&group->order);
+  bn_set_minimal_width(&group->order);
 
   BN_MONT_CTX_free(group->order_mont);
   group->order_mont = BN_MONT_CTX_new_for_modulus(&group->order, NULL);
@@ -817,8 +817,7 @@
 
   ERR_clear_error();
 
-  // This is an unusual input, so we do not guarantee constant-time
-  // processing, even ignoring |bn_correct_top|.
+  // This is an unusual input, so we do not guarantee constant-time processing.
   const BIGNUM *order = &group->order;
   BN_CTX_start(ctx);
   BIGNUM *tmp = BN_CTX_get(ctx);
@@ -946,7 +945,7 @@
   if (!ec_bignum_to_scalar_unchecked(group, out, in)) {
     return 0;
   }
-  if (!bn_less_than_words(out->words, group->order.d, group->order.top)) {
+  if (!bn_less_than_words(out->words, group->order.d, group->order.width)) {
     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
     return 0;
   }
@@ -955,7 +954,7 @@
 
 int ec_bignum_to_scalar_unchecked(const EC_GROUP *group, EC_SCALAR *out,
                                   const BIGNUM *in) {
-  if (!bn_copy_words(out->words, group->order.top, in)) {
+  if (!bn_copy_words(out->words, group->order.width, in)) {
     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
     return 0;
   }
@@ -964,6 +963,6 @@
 
 int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
                              const uint8_t additional_data[32]) {
-  return bn_rand_range_words(out->words, 1, group->order.d, group->order.top,
+  return bn_rand_range_words(out->words, 1, group->order.d, group->order.width,
                              additional_data);
 }
diff --git a/crypto/fipsmodule/ec/ec_test.cc b/crypto/fipsmodule/ec/ec_test.cc
index 260b972..923ce1e 100644
--- a/crypto/fipsmodule/ec/ec_test.cc
+++ b/crypto/fipsmodule/ec/ec_test.cc
@@ -506,9 +506,8 @@
       << "p * order did not return point at infinity.";
 }
 
-// Test that |EC_POINT_mul| works with out-of-range scalars. Even beyond the
-// usual |bn_correct_top| disclaimer, we completely disclaim all hope here as a
-// reduction is needed, but we'll compute the right answer.
+// Test that |EC_POINT_mul| works with out-of-range scalars. The operation will
+// not be constant-time, but we'll compute the right answer.
 TEST_P(ECCurveTest, MulOutOfRange) {
   bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
   ASSERT_TRUE(group);
diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h
index 06fa371..4fde7fa 100644
--- a/crypto/fipsmodule/ec/internal.h
+++ b/crypto/fipsmodule/ec/internal.h
@@ -92,8 +92,8 @@
                        bn_small_functions_applicable);
 
 // An EC_SCALAR is an integer fully reduced modulo the order. Only the first
-// |order->top| words are used. An |EC_SCALAR| is specific to an |EC_GROUP| and
-// must not be mixed between groups.
+// |order->width| words are used. An |EC_SCALAR| is specific to an |EC_GROUP|
+// and must not be mixed between groups.
 typedef union {
   // bytes is the representation of the scalar in little-endian order.
   uint8_t bytes[EC_MAX_SCALAR_BYTES];
diff --git a/crypto/fipsmodule/ec/simple.c b/crypto/fipsmodule/ec/simple.c
index 8bc20a4..08954ea 100644
--- a/crypto/fipsmodule/ec/simple.c
+++ b/crypto/fipsmodule/ec/simple.c
@@ -136,7 +136,7 @@
   }
   BN_set_negative(&group->field, 0);
   // Store the field in minimal form, so it can be used with |BN_ULONG| arrays.
-  bn_correct_top(&group->field);
+  bn_set_minimal_width(&group->field);
 
   // group->a
   if (!BN_nnmod(tmp_a, a, &group->field, ctx)) {
diff --git a/crypto/fipsmodule/ec/wnaf.c b/crypto/fipsmodule/ec/wnaf.c
index 5b2ae1e..1fd2f24 100644
--- a/crypto/fipsmodule/ec/wnaf.c
+++ b/crypto/fipsmodule/ec/wnaf.c
@@ -150,7 +150,7 @@
 
     window_val >>= 1;
     window_val +=
-        bit * bn_is_bit_set_words(scalar->words, group->order.top, j + w);
+        bit * bn_is_bit_set_words(scalar->words, group->order.width, j + w);
 
     if (window_val > next_bit) {
       OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
diff --git a/crypto/fipsmodule/ecdsa/ecdsa.c b/crypto/fipsmodule/ecdsa/ecdsa.c
index 9e038de..c5159df 100644
--- a/crypto/fipsmodule/ecdsa/ecdsa.c
+++ b/crypto/fipsmodule/ecdsa/ecdsa.c
@@ -80,11 +80,12 @@
   //   |a| + |b| < 2^BN_num_bits(order) + order
   // so this leaves |r| < 2^BN_num_bits(order).
   const BIGNUM *order = &group->order;
-  BN_ULONG carry = bn_add_words(r->words, a->words, b->words, order->top);
+  BN_ULONG carry = bn_add_words(r->words, a->words, b->words, order->width);
   EC_LOOSE_SCALAR tmp;
-  BN_ULONG v = bn_sub_words(tmp.words, r->words, order->d, order->top) - carry;
+  BN_ULONG v =
+      bn_sub_words(tmp.words, r->words, order->d, order->width) - carry;
   v = 0u - v;
-  for (int i = 0; i < order->top; i++) {
+  for (int i = 0; i < order->width; i++) {
     OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
                            crypto_word_t_too_small);
     r->words[i] = constant_time_select_w(v, r->words[i], tmp.words[i]);
@@ -94,8 +95,9 @@
 static int scalar_mod_mul_montgomery(const EC_GROUP *group, EC_SCALAR *r,
                                      const EC_SCALAR *a, const EC_SCALAR *b) {
   const BIGNUM *order = &group->order;
-  return bn_mod_mul_montgomery_small(r->words, order->top, a->words, order->top,
-                                     b->words, order->top, group->order_mont);
+  return bn_mod_mul_montgomery_small(r->words, order->width, a->words,
+                                     order->width, b->words, order->width,
+                                     group->order_mont);
 }
 
 static int scalar_mod_mul_montgomery_loose(const EC_GROUP *group, EC_SCALAR *r,
@@ -105,8 +107,9 @@
   // product not exceed R * |order|. |b| is fully reduced and |a| <
   // 2^BN_num_bits(order) <= R, so this holds.
   const BIGNUM *order = &group->order;
-  return bn_mod_mul_montgomery_small(r->words, order->top, a->words, order->top,
-                                     b->words, order->top, group->order_mont);
+  return bn_mod_mul_montgomery_small(r->words, order->width, a->words,
+                                     order->width, b->words, order->width,
+                                     group->order_mont);
 }
 
 // digest_to_scalar interprets |digest_len| bytes from |digest| as a scalar for
@@ -128,11 +131,11 @@
   // If still too long truncate remaining bits with a shift
   if (8 * digest_len > num_bits) {
     size_t shift = 8 - (num_bits & 0x7);
-    for (int i = 0; i < order->top - 1; i++) {
+    for (int i = 0; i < order->width - 1; i++) {
       out->words[i] =
           (out->words[i] >> shift) | (out->words[i + 1] << (BN_BITS2 - shift));
     }
-    out->words[order->top - 1] >>= shift;
+    out->words[order->width - 1] >>= shift;
   }
 }
 
@@ -255,8 +258,8 @@
       // TODO(davidben): Add a words version of |BN_mod_inverse_odd| and write
       // into |s_inv_mont| directly.
       !ec_bignum_to_scalar_unchecked(group, &s_inv_mont, X) ||
-      !bn_to_montgomery_small(s_inv_mont.words, order->top, s_inv_mont.words,
-                              order->top, group->order_mont)) {
+      !bn_to_montgomery_small(s_inv_mont.words, order->width, s_inv_mont.words,
+                              order->width, group->order_mont)) {
     goto err;
   }
   // u1 = m * s^-1 mod order
@@ -343,7 +346,7 @@
       SHA512_CTX sha;
       uint8_t additional_data[SHA512_DIGEST_LENGTH];
       SHA512_Init(&sha);
-      SHA512_Update(&sha, priv_key->words, order->top * sizeof(BN_ULONG));
+      SHA512_Update(&sha, priv_key->words, order->width * sizeof(BN_ULONG));
       SHA512_Update(&sha, digest, digest_len);
       SHA512_Final(additional_data, &sha);
       if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
@@ -353,10 +356,10 @@
 
     // Compute k^-1. We leave it in the Montgomery domain as an optimization for
     // later operations.
-    if (!bn_to_montgomery_small(out_kinv_mont->words, order->top, k.words,
-                                order->top, group->order_mont) ||
-        !bn_mod_inverse_prime_mont_small(out_kinv_mont->words, order->top,
-                                         out_kinv_mont->words, order->top,
+    if (!bn_to_montgomery_small(out_kinv_mont->words, order->width, k.words,
+                                order->width, group->order_mont) ||
+        !bn_mod_inverse_prime_mont_small(out_kinv_mont->words, order->width,
+                                         out_kinv_mont->words, order->width,
                                          group->order_mont)) {
       goto err;
     }
@@ -426,8 +429,8 @@
     // Montgomery domain, |scalar_mod_mul_montgomery| will compute the answer in
     // the normal domain.
     if (!ec_bignum_to_scalar(group, &r_mont, ret->r) ||
-        !bn_to_montgomery_small(r_mont.words, order->top, r_mont.words,
-                                order->top, group->order_mont) ||
+        !bn_to_montgomery_small(r_mont.words, order->width, r_mont.words,
+                                order->width, group->order_mont) ||
         !scalar_mod_mul_montgomery(group, &s, &priv_key, &r_mont)) {
       goto err;
     }
@@ -438,7 +441,7 @@
     // Finally, multiply s by k^-1. That was retained in Montgomery form, so the
     // same technique as the previous multiplication works.
     if (!scalar_mod_mul_montgomery_loose(group, &s, &tmp, &kinv_mont) ||
-        !bn_set_words(ret->s, s.words, order->top)) {
+        !bn_set_words(ret->s, s.words, order->width)) {
       goto err;
     }
     if (!BN_is_zero(ret->s)) {
diff --git a/crypto/fipsmodule/rsa/rsa.c b/crypto/fipsmodule/rsa/rsa.c
index ffe2cd0..bde81aa 100644
--- a/crypto/fipsmodule/rsa/rsa.c
+++ b/crypto/fipsmodule/rsa/rsa.c
@@ -760,8 +760,8 @@
 
 DEFINE_LOCAL_DATA(BIGNUM, g_small_factors) {
   out->d = (BN_ULONG *) kSmallFactorsLimbs;
-  out->top = OPENSSL_ARRAY_SIZE(kSmallFactorsLimbs);
-  out->dmax = out->top;
+  out->width = OPENSSL_ARRAY_SIZE(kSmallFactorsLimbs);
+  out->dmax = out->width;
   out->neg = 0;
   out->flags = BN_FLG_STATIC_DATA;
 }
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
index 7f7d479..4e9d54f 100644
--- a/include/openssl/bn.h
+++ b/include/openssl/bn.h
@@ -907,12 +907,30 @@
 // Private functions
 
 struct bignum_st {
-  BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian
-                  order. */
-  int top;    // Index of last used element in |d|, plus one.
-  int dmax;   // Size of |d|, in words.
-  int neg;    // one if the number is negative
-  int flags;  // bitmask of BN_FLG_* values
+  // d is a pointer to an array of |width| |BN_BITS2|-bit chunks in
+  // little-endian order. This stores the absolute value of the number.
+  BN_ULONG *d;
+  // width is the number of elements of |d| which are valid. This value is not
+  // necessarily minimal; the most-significant words of |d| may be zero.
+  // |width| determines a potentially loose upper-bound on the absolute value
+  // of the |BIGNUM|.
+  //
+  // Functions taking |BIGNUM| inputs must compute the same answer for all
+  // possible widths. |bn_minimal_width|, |bn_set_minimal_width|, and other
+  // helpers may be used to recover the minimal width, provided it is not
+  // secret. If it is secret, use a different algorithm. Functions may output
+  // minimal or non-minimal |BIGNUM|s depending on secrecy requirements, but
+  // those which cause widths to unboundedly grow beyond the minimal value
+  // should be documented such.
+  //
+  // Note this is different from historical |BIGNUM| semantics.
+  int width;
+  // dmax is number of elements of |d| which are allocated.
+  int dmax;
+  // neg is one if the number if negative and zero otherwise.
+  int neg;
+  // flags is a bitmask of |BN_FLG_*| values
+  int flags;
 };
 
 struct bn_mont_ctx_st {