Add a test for BN_cmp_word.

This also adds a missing OPENSSL_EXPORT.

Change-Id: I6c2400246280f68f51157e959438644976b1171b
Reviewed-on: https://boringssl-review.googlesource.com/9041
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc
index 20f64d6..14dcead 100644
--- a/crypto/bn/bn_test.cc
+++ b/crypto/bn/bn_test.cc
@@ -1291,6 +1291,77 @@
   return true;
 }
 
+static bool TestCmpWord() {
+  static const BN_ULONG kMaxWord = (BN_ULONG)-1;
+
+  ScopedBIGNUM r(BN_new());
+  if (!r ||
+      !BN_set_word(r.get(), 0)) {
+    return false;
+  }
+
+  if (BN_cmp_word(r.get(), 0) != 0 ||
+      BN_cmp_word(r.get(), 1) >= 0 ||
+      BN_cmp_word(r.get(), kMaxWord) >= 0) {
+    fprintf(stderr, "BN_cmp_word compared against 0 incorrectly.\n");
+    return false;
+  }
+
+  if (!BN_set_word(r.get(), 100)) {
+    return false;
+  }
+
+  if (BN_cmp_word(r.get(), 0) <= 0 ||
+      BN_cmp_word(r.get(), 99) <= 0 ||
+      BN_cmp_word(r.get(), 100) != 0 ||
+      BN_cmp_word(r.get(), 101) >= 0 ||
+      BN_cmp_word(r.get(), kMaxWord) >= 0) {
+    fprintf(stderr, "BN_cmp_word compared against 100 incorrectly.\n");
+    return false;
+  }
+
+  BN_set_negative(r.get(), 1);
+
+  if (BN_cmp_word(r.get(), 0) >= 0 ||
+      BN_cmp_word(r.get(), 100) >= 0 ||
+      BN_cmp_word(r.get(), kMaxWord) >= 0) {
+    fprintf(stderr, "BN_cmp_word compared against -100 incorrectly.\n");
+    return false;
+  }
+
+  if (!BN_set_word(r.get(), kMaxWord)) {
+    return false;
+  }
+
+  if (BN_cmp_word(r.get(), 0) <= 0 ||
+      BN_cmp_word(r.get(), kMaxWord - 1) <= 0 ||
+      BN_cmp_word(r.get(), kMaxWord) != 0) {
+    fprintf(stderr, "BN_cmp_word compared against kMaxWord incorrectly.\n");
+    return false;
+  }
+
+  if (!BN_add(r.get(), r.get(), BN_value_one())) {
+    return false;
+  }
+
+  if (BN_cmp_word(r.get(), 0) <= 0 ||
+      BN_cmp_word(r.get(), kMaxWord) <= 0) {
+    fprintf(stderr, "BN_cmp_word compared against kMaxWord + 1 incorrectly.\n");
+    return false;
+  }
+
+  BN_set_negative(r.get(), 1);
+
+  if (BN_cmp_word(r.get(), 0) >= 0 ||
+      BN_cmp_word(r.get(), kMaxWord) >= 0) {
+    fprintf(stderr,
+            "BN_cmp_word compared against -kMaxWord - 1 incorrectly.\n");
+    return false;
+  }
+
+  return true;
+}
+
 int main(int argc, char *argv[]) {
   CRYPTO_library_init();
 
@@ -1314,7 +1385,8 @@
       !TestNegativeZero(ctx.get()) ||
       !TestBadModulus(ctx.get()) ||
       !TestExpModZero() ||
-      !TestSmallPrime(ctx.get())) {
+      !TestSmallPrime(ctx.get()) ||
+      !TestCmpWord()) {
     return 1;
   }
 
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
index 51a63e6..0b5af6a 100644
--- a/include/openssl/bn.h
+++ b/include/openssl/bn.h
@@ -438,7 +438,7 @@
 
 /* BN_cmp_word is like |BN_cmp| except it takes its second argument as a
  * |BN_ULONG| instead of a |BIGNUM|. */
-int BN_cmp_word(const BIGNUM *a, BN_ULONG b);
+OPENSSL_EXPORT int BN_cmp_word(const BIGNUM *a, BN_ULONG b);
 
 /* BN_ucmp returns a value less than, equal to or greater than zero if the
  * absolute value of |a| is less than, equal to or greater than the absolute