Remove remaining running pointers in BN_div

Expressing everything in terms of i makes it at lot easier to tell what
words are being written to where, and convince oneself that everything
stays in bounds. I kept a wnum variable in there since it's used so
frequently but added a note about the bounds. In a higher-level
language, wnum would be a slice of width div_n + 1.

Bug: 358687140
Change-Id: Iae39b1915f80008ab5ed91e1e7fc5cd1349e8c1e
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/70227
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/bn/div.c b/crypto/fipsmodule/bn/div.c
index f1588c1..aa2e2e5 100644
--- a/crypto/fipsmodule/bn/div.c
+++ b/crypto/fipsmodule/bn/div.c
@@ -236,15 +236,6 @@
   }
 
   int loop = num_n - div_n;
-  // Lets setup a 'window' into snum
-  // This is the part that corresponds to the current
-  // 'area' being divided
-  BIGNUM wnum;
-  wnum.neg = 0;
-  wnum.d = &(snum->d[loop]);
-  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.
   const BN_ULONG d0 = sdiv->d[div_n - 1];
@@ -253,9 +244,6 @@
   // The normalization step ensures that |sdiv|'s MSB is one.
   assert(d0 & (((BN_ULONG)1) << (BN_BITS2 - 1)));
 
-  // pointer to the 'top' of snum
-  BN_ULONG *wnump = &(snum->d[num_n - 1]);
-
   // Setup |res|. |numerator| and |res| may alias, so we save |numerator->neg|
   // for later.
   const int numerator_neg = numerator->neg;
@@ -273,19 +261,19 @@
   // division. Note that Knuth indexes words from most to least significant, so
   // our index is reversed. Each loop iteration computes res->d[i] of the
   // quotient and updates snum with the running remainder. Before each loop
-  // iteration, wnum <= sdiv.
-  for (int i = loop - 1; i >= 0; i--, wnump--) {
-    // TODO(crbug.com/358687140): Remove these running pointers.
-    wnum.d--;
-    assert(wnum.d == snum->d + i);
-    assert(wnump == wnum.d + div_n);
-
-    // Knuth step D3: Compute q', an estimate of q = floor(wnum / sdiv) by
-    // looking at the top words. We must estimate such that q' = q or
-    // q' = q + 1.
+  // iteration, the div_n words beginning at snum->d[i+1] must be less than
+  // snum.
+  for (int i = loop - 1; i >= 0; i--) {
+    // The next word of the quotient, q, is floor(wnum / sdiv), where wnum is
+    // the div_n + 1 words beginning at snum->d[i]. i starts at
+    // num_n - div_n - 1, so there are at least div_n + 1 words available.
+    //
+    // Knuth step D3: Compute q', an estimate of q by looking at the top words
+    // of wnum and sdiv. We must estimate such that q' = q or q' = q + 1.
     BN_ULONG q, rm = 0;
-    BN_ULONG n0 = wnump[0];
-    BN_ULONG n1 = wnump[-1];
+    BN_ULONG *wnum = snum->d + i;
+    BN_ULONG n0 = wnum[div_n];
+    BN_ULONG n1 = wnum[div_n - 1];
     if (n0 == d0) {
       // Estimate q' = b - 1, where b is the base.
       q = BN_MASK2;
@@ -325,10 +313,11 @@
       // q + 1, Knuth uses a loop. A loop will often also correct q + 1 to q,
       // saving the slightly more expensive underflow handling below.
       if (div_n > 1) {
+        BN_ULONG n2 = wnum[div_n - 2];
 #ifdef BN_ULLONG
         BN_ULLONG t2 = (BN_ULLONG)d1 * q;
         for (;;) {
-          if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | wnump[-2])) {
+          if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | n2)) {
             break;
           }
           q--;
@@ -344,7 +333,7 @@
         BN_ULONG t2l, t2h;
         BN_UMULT_LOHI(t2l, t2h, d1, q);
         for (;;) {
-          if (t2h < rm || (t2h == rm && t2l <= wnump[-2])) {
+          if (t2h < rm || (t2h == rm && t2l <= n2)) {
             break;
           }
           q--;
@@ -367,10 +356,10 @@
     // -sdiv < wnum - sdiv * q < sdiv. If q' = q + 1, the subtraction will
     // underflow, and we fix it up below.
     tmp->d[div_n] = bn_mul_words(tmp->d, sdiv->d, div_n, q);
-    if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) {
+    if (bn_sub_words(wnum, wnum, tmp->d, div_n + 1)) {
       q--;
       // The final addition is expected to overflow, canceling the underflow.
-      wnum.d[div_n] += bn_add_words(wnum.d, wnum.d, sdiv->d, div_n);
+      wnum[div_n] += bn_add_words(wnum, wnum, sdiv->d, div_n);
     }
 
     // q is now correct, and wnum has been updated to the running remainder.