Rewrite scalar operations in spake25519.c with BN_ULONG

This reuses code we already have, and also avoids another union.

Bug: 301
Change-Id: I2f4ab564cf220818ca96d9c99a122c1e5cdc9e7a
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53228
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/curve25519/spake25519.c b/crypto/curve25519/spake25519.c
index f750911..c45d15a 100644
--- a/crypto/curve25519/spake25519.c
+++ b/crypto/curve25519/spake25519.c
@@ -22,6 +22,7 @@
 #include <openssl/rand.h>
 #include <openssl/sha.h>
 
+#include "../fipsmodule/bn/internal.h"
 #include "../internal.h"
 #include "./internal.h"
 
@@ -314,46 +315,30 @@
   }
 }
 
-typedef union {
-  uint8_t bytes[32];
-  uint32_t words[8];
+typedef struct {
+  BN_ULONG words[32 / sizeof(BN_ULONG)];
 } scalar;
 
-// kOrder is the order of the prime-order subgroup of curve25519 in
-// little-endian order.
-static const scalar kOrder = {{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
-                               0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}};
+// kOrder is the order of the prime-order subgroup of curve25519.
+static const scalar kOrder = {
+    {TOBN(0x5812631a, 0x5cf5d3ed), TOBN(0x14def9de, 0xa2f79cd6),
+     TOBN(0x00000000, 0x00000000), TOBN(0x10000000, 0x00000000)}};
 
 // scalar_cmov copies |src| to |dest| if |mask| is all ones.
 static void scalar_cmov(scalar *dest, const scalar *src, crypto_word_t mask) {
-  for (size_t i = 0; i < 8; i++) {
-    dest->words[i] =
-        constant_time_select_w(mask, src->words[i], dest->words[i]);
-  }
+  bn_select_words(dest->words, mask, src->words, dest->words,
+                  OPENSSL_ARRAY_SIZE(dest->words));
 }
 
 // scalar_double sets |s| to |2×s|.
 static void scalar_double(scalar *s) {
-  uint32_t carry = 0;
-
-  for (size_t i = 0; i < 8; i++) {
-    const uint32_t carry_out = s->words[i] >> 31;
-    s->words[i] = (s->words[i] << 1) | carry;
-    carry = carry_out;
-  }
+  bn_add_words(s->words, s->words, s->words, OPENSSL_ARRAY_SIZE(s->words));
 }
 
 // scalar_add sets |dest| to |dest| plus |src|.
 static void scalar_add(scalar *dest, const scalar *src) {
-  uint32_t carry = 0;
-
-  for (size_t i = 0; i < 8; i++) {
-    uint64_t tmp = ((uint64_t)dest->words[i] + src->words[i]) + carry;
-    dest->words[i] = (uint32_t)tmp;
-    carry = (uint32_t)(tmp >> 32);
-  }
+  bn_add_words(dest->words, dest->words, src->words,
+               OPENSSL_ARRAY_SIZE(dest->words));
 }
 
 int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len,
@@ -412,25 +397,25 @@
 
     OPENSSL_memset(&tmp, 0, sizeof(tmp));
     scalar_cmov(&tmp, &order,
-                constant_time_eq_w(password_scalar.bytes[0] & 1, 1));
+                constant_time_eq_w(password_scalar.words[0] & 1, 1));
     scalar_add(&password_scalar, &tmp);
 
     scalar_double(&order);
     OPENSSL_memset(&tmp, 0, sizeof(tmp));
     scalar_cmov(&tmp, &order,
-                constant_time_eq_w(password_scalar.bytes[0] & 2, 2));
+                constant_time_eq_w(password_scalar.words[0] & 2, 2));
     scalar_add(&password_scalar, &tmp);
 
     scalar_double(&order);
     OPENSSL_memset(&tmp, 0, sizeof(tmp));
     scalar_cmov(&tmp, &order,
-                constant_time_eq_w(password_scalar.bytes[0] & 4, 4));
+                constant_time_eq_w(password_scalar.words[0] & 4, 4));
     scalar_add(&password_scalar, &tmp);
 
-    assert((password_scalar.bytes[0] & 7) == 0);
+    assert((password_scalar.words[0] & 7) == 0);
   }
 
-  OPENSSL_memcpy(ctx->password_scalar, password_scalar.bytes,
+  OPENSSL_memcpy(ctx->password_scalar, password_scalar.words,
                  sizeof(ctx->password_scalar));
 
   ge_p3 mask;