Add ABI tests for AES-GCM-SIV assembly

Change-Id: I8051799ba060758e74c3fcaa7ede616321c9c1c9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/98428
Reviewed-by: Adam Langley <agl@google.com>
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Adam Langley <agl@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc
index 5866112..c3b83b1 100644
--- a/crypto/cipher/aead_test.cc
+++ b/crypto/cipher/aead_test.cc
@@ -1383,6 +1383,71 @@
 #endif
   }
 }
+
+#if defined(AES_GCM_SIV_ASM)
+TEST(AESGCMSIVTest, ABI) {
+  if (!aes_gcm_siv_asm_capable()) {
+    return;
+  }
+
+  uint8_t key128[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+  uint8_t key256[32] = {1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11,
+                        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+                        23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
+  aead_aes_gcm_siv_asm_ctx ctx128, ctx256;
+  CHECK_ABI(aes128gcmsiv_aes_ks, key128, &ctx128.key[0]);
+  ctx128.is_128_bit = 1;
+  CHECK_ABI(aes256gcmsiv_aes_ks, key256, &ctx256.key[0]);
+  ctx256.is_128_bit = 0;
+
+  alignas(16) uint8_t block[16] = {1, 2,  3,  4,  5,  6,  7,  8,
+                                   9, 10, 11, 12, 13, 14, 15, 16};
+  alignas(16) uint8_t out_block[16];
+  alignas(16) uint8_t expanded_key[16 * 15];
+  alignas(16) uint64_t record_enc_key[4] = {1, 2, 3, 4};
+  CHECK_ABI(aes128gcmsiv_aes_ks_enc_x1, block, out_block, expanded_key,
+            record_enc_key);
+  CHECK_ABI(aes256gcmsiv_aes_ks_enc_x1, block, out_block, expanded_key,
+            record_enc_key);
+
+  CHECK_ABI(aes128gcmsiv_ecb_enc_block, block, out_block, &ctx128);
+  CHECK_ABI(aes256gcmsiv_ecb_enc_block, block, out_block, &ctx256);
+
+  alignas(16) uint8_t padded_nonce[16] = {1, 2,  3,  4,  5, 6, 7, 8,
+                                          9, 10, 11, 12, 0, 0, 0, 0};
+  alignas(16) uint64_t out_key_material[12];
+  CHECK_ABI(aes128gcmsiv_kdf, padded_nonce, out_key_material, &ctx128.key[0]);
+  CHECK_ABI(aes256gcmsiv_kdf, padded_nonce, out_key_material, &ctx256.key[0]);
+
+  alignas(16) uint8_t auth_key[16] = {1, 2,  3,  4,  5,  6,  7,  8,
+                                      9, 10, 11, 12, 13, 14, 15, 16};
+  alignas(16) uint8_t htable8[16 * 8];
+  alignas(16) uint8_t htable6[16 * 6];
+  CHECK_ABI(aesgcmsiv_htable_init, htable8, auth_key);
+  CHECK_ABI(aesgcmsiv_htable6_init, htable6, auth_key);
+
+  uint8_t buf[256] = {0};
+  uint8_t out_buf[256] = {0};
+  alignas(16) uint8_t poly[16] = {0};
+  for (size_t blocks : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) {
+    CHECK_ABI(aesgcmsiv_polyval_horner, poly, auth_key, buf, blocks);
+  }
+
+  alignas(16) uint8_t tag[16] = {0};
+  alignas(16) uint8_t calculated_tag_and_scratch[16 * 8] = {0};
+  for (size_t len : {0, 16, 32, 48, 64, 80, 96, 112, 128, 144}) {
+    CHECK_ABI(aesgcmsiv_htable_polyval, htable8, buf, len, poly);
+    CHECK_ABI(aes128gcmsiv_enc_msg_x4, buf, out_buf, tag, &ctx128, len);
+    CHECK_ABI(aes256gcmsiv_enc_msg_x4, buf, out_buf, tag, &ctx256, len);
+    CHECK_ABI(aes128gcmsiv_enc_msg_x8, buf, out_buf, tag, &ctx128, len);
+    CHECK_ABI(aes256gcmsiv_enc_msg_x8, buf, out_buf, tag, &ctx256, len);
+    CHECK_ABI(aes128gcmsiv_dec, buf, out_buf, calculated_tag_and_scratch,
+              htable6, &ctx128, len);
+    CHECK_ABI(aes256gcmsiv_dec, buf, out_buf, calculated_tag_and_scratch,
+              htable6, &ctx256, len);
+  }
+}
+#endif  // AES_GCM_SIV_ASM
 #endif  // SUPPORTS_ABI_TEST
 
 TEST(AEADTest, AESCCMLargeAD) {
diff --git a/crypto/cipher/e_aesgcmsiv.cc b/crypto/cipher/e_aesgcmsiv.cc
index 5ab7c32..4a3eb03 100644
--- a/crypto/cipher/e_aesgcmsiv.cc
+++ b/crypto/cipher/e_aesgcmsiv.cc
@@ -24,6 +24,7 @@
 #include "../fipsmodule/aes/internal.h"
 #include "../fipsmodule/cipher/internal.h"
 #include "../internal.h"
+#include "internal.h"
 
 
 using namespace bssl;
@@ -36,18 +37,7 @@
   CRYPTO_store_u32_le(tag, CRYPTO_load_u32_le(tag) + by);
 }
 
-// TODO(davidben): AES-GCM-SIV assembly is not correct for Windows. It must save
-// and restore xmm6 through xmm15.
-#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
-    !defined(OPENSSL_WINDOWS)
-#define AES_GCM_SIV_ASM
-
-// Optimised AES-GCM-SIV
-
-struct aead_aes_gcm_siv_asm_ctx {
-  alignas(16) uint8_t key[16 * 15];
-  int is_128_bit;
-};
+#if defined(AES_GCM_SIV_ASM)
 
 // The assembly code assumes 8-byte alignment of the EVP_AEAD_CTX's state, and
 // aligns to 16 bytes itself.
@@ -57,141 +47,6 @@
 static_assert(alignof(union evp_aead_ctx_st_state) >= 8,
               "AEAD state has insufficient alignment");
 
-extern "C" {
-// aes128gcmsiv_aes_ks writes an AES-128 key schedule for `key` to
-// `out_expanded_key`. `out_expanded_key` must be 16-byte aligned.
-extern void aes128gcmsiv_aes_ks(const uint8_t key[16],
-                                uint8_t out_expanded_key[16 * 15]);
-
-// aes256gcmsiv_aes_ks writes an AES-256 key schedule for `key` to
-// `out_expanded_key`. `out_expanded_key` must be 16-byte aligned.
-extern void aes256gcmsiv_aes_ks(const uint8_t key[32],
-                                uint8_t out_expanded_key[16 * 15]);
-
-// aesgcmsiv_polyval_horner updates the POLYVAL value in `in_out_poly` to
-// include a number (`in_blocks`) of 16-byte blocks of data from `in`, given
-// the POLYVAL key in `key`. `in_out_poly` and `key` must be 16-byte aligned.
-extern void aesgcmsiv_polyval_horner(const uint8_t in_out_poly[16],
-                                     const uint8_t key[16], const uint8_t *in,
-                                     size_t in_blocks);
-
-// aesgcmsiv_htable_init writes powers 1..8 of `auth_key` to `out_htable`.
-// `out_htable` and `auth_key` must be 16-byte aligned.
-extern void aesgcmsiv_htable_init(uint8_t out_htable[16 * 8],
-                                  const uint8_t auth_key[16]);
-
-// aesgcmsiv_htable6_init writes powers 1..6 of `auth_key` to `out_htable`.
-// `out_htable` and `auth_key` must be 16-byte aligned.
-extern void aesgcmsiv_htable6_init(uint8_t out_htable[16 * 6],
-                                   const uint8_t auth_key[16]);
-
-// aesgcmsiv_htable_polyval updates the POLYVAL value in `in_out_poly` to
-// include `in_len` bytes of data from `in`. (Where `in_len` must be a multiple
-// of 16.) It uses the precomputed powers of the key given in `htable`.
-// `in_out_poly` and `htable` must be 16-byte aligned.
-extern void aesgcmsiv_htable_polyval(const uint8_t htable[16 * 8],
-                                     const uint8_t *in, size_t in_len,
-                                     uint8_t in_out_poly[16]);
-
-// aes128gcmsiv_dec decrypts `in_len` & ~15 bytes from `out` and writes them to
-// `in`. `in` and `out` may be equal, but must not otherwise alias.
-//
-// `in_out_calculated_tag_and_scratch`, on entry, must contain:
-//    1. The current value of the calculated tag, which will be updated during
-//       decryption and written back to the beginning of this buffer on exit.
-//    2. The claimed tag, which is needed to derive counter values.
-//
-// While decrypting, the whole of `in_out_calculated_tag_and_scratch` may be
-// used for other purposes. `in_out_calculated_tag_and_scratch` and `htable`
-// must be 16-byte aligned. In order to decrypt and update the POLYVAL value, it
-// uses the expanded key from `key` and the table of powers in `htable`.
-extern void aes128gcmsiv_dec(const uint8_t *in, uint8_t *out,
-                             uint8_t in_out_calculated_tag_and_scratch[16 * 8],
-                             const uint8_t htable[16 * 6],
-                             const struct aead_aes_gcm_siv_asm_ctx *key,
-                             size_t in_len);
-
-// aes256gcmsiv_dec acts like `aes128gcmsiv_dec`, but for AES-256.
-// `in_out_calculated_tag_and_scratch` and `htable` must be 16-byte aligned.
-extern void aes256gcmsiv_dec(const uint8_t *in, uint8_t *out,
-                             uint8_t in_out_calculated_tag_and_scratch[16 * 8],
-                             const uint8_t htable[16 * 6],
-                             const struct aead_aes_gcm_siv_asm_ctx *key,
-                             size_t in_len);
-
-// aes128gcmsiv_kdf performs the AES-GCM-SIV KDF given the expanded key from
-// `key_schedule` and the nonce in `nonce`. Note that, while only 12 bytes of
-// the nonce are used, 16 bytes are read and so the value must be
-// right-padded. `nonce`, `out_key_material`, and `key_schedule` must be
-// 16-byte aligned.
-extern void aes128gcmsiv_kdf(const uint8_t nonce[16],
-                             uint64_t out_key_material[8],
-                             const uint8_t *key_schedule);
-
-// aes256gcmsiv_kdf acts like `aes128gcmsiv_kdf`, but for AES-256. `nonce`,
-// `out_key_material`, and `key_schedule` must be 16-byte aligned.
-extern void aes256gcmsiv_kdf(const uint8_t nonce[16],
-                             uint64_t out_key_material[12],
-                             const uint8_t *key_schedule);
-
-// aes128gcmsiv_aes_ks_enc_x1 performs a key expansion of the AES-128 key in
-// `key`, writes the expanded key to `out_expanded_key` and encrypts a single
-// block from `in` to `out`. `in`, `out`, `out_expanded_key`, and `key` must be
-// 16-byte aligned.
-extern void aes128gcmsiv_aes_ks_enc_x1(const uint8_t in[16], uint8_t out[16],
-                                       uint8_t out_expanded_key[16 * 15],
-                                       const uint64_t key[2]);
-
-// aes256gcmsiv_aes_ks_enc_x1 acts like `aes128gcmsiv_aes_ks_enc_x1`, but for
-// AES-256. `in`, `out`, `out_expanded_key`, and `key` must be 16-byte aligned.
-extern void aes256gcmsiv_aes_ks_enc_x1(const uint8_t in[16], uint8_t out[16],
-                                       uint8_t out_expanded_key[16 * 15],
-                                       const uint64_t key[4]);
-
-// aes128gcmsiv_ecb_enc_block encrypts a single block from `in` to `out` using
-// the expanded key in `expanded_key`. `in` and `out` must be 16-byte aligned.
-extern void aes128gcmsiv_ecb_enc_block(
-    const uint8_t in[16], uint8_t out[16],
-    const struct aead_aes_gcm_siv_asm_ctx *expanded_key);
-
-// aes256gcmsiv_ecb_enc_block acts like `aes128gcmsiv_ecb_enc_block`, but for
-// AES-256. `in` and `out` must be 16-byte aligned.
-extern void aes256gcmsiv_ecb_enc_block(
-    const uint8_t in[16], uint8_t out[16],
-    const struct aead_aes_gcm_siv_asm_ctx *expanded_key);
-
-// aes128gcmsiv_enc_msg_x4 encrypts `in_len` bytes from `in` to `out` using the
-// expanded key from `key`. (The value of `in_len` must be a multiple of 16.)
-// The `in` and `out` buffers may be equal but must not otherwise overlap. The
-// initial counter is constructed from the given `tag` as required by
-// AES-GCM-SIV. `tag` must be 16-byte aligned.
-extern void aes128gcmsiv_enc_msg_x4(const uint8_t *in, uint8_t *out,
-                                    const uint8_t *tag,
-                                    const struct aead_aes_gcm_siv_asm_ctx *key,
-                                    size_t in_len);
-
-// aes256gcmsiv_enc_msg_x4 acts like `aes128gcmsiv_enc_msg_x4`, but for
-// AES-256. `tag` must be 16-byte aligned.
-extern void aes256gcmsiv_enc_msg_x4(const uint8_t *in, uint8_t *out,
-                                    const uint8_t *tag,
-                                    const struct aead_aes_gcm_siv_asm_ctx *key,
-                                    size_t in_len);
-
-// aes128gcmsiv_enc_msg_x8 acts like `aes128gcmsiv_enc_msg_x4`, but is
-// optimised for longer messages.
-extern void aes128gcmsiv_enc_msg_x8(const uint8_t *in, uint8_t *out,
-                                    const uint8_t *tag,
-                                    const struct aead_aes_gcm_siv_asm_ctx *key,
-                                    size_t in_len);
-
-// aes256gcmsiv_enc_msg_x8 acts like `aes256gcmsiv_enc_msg_x4`, but is
-// optimised for longer messages.
-extern void aes256gcmsiv_enc_msg_x8(const uint8_t *in, uint8_t *out,
-                                    const uint8_t *tag,
-                                    const struct aead_aes_gcm_siv_asm_ctx *key,
-                                    size_t in_len);
-}
-
 // asm_ctx_from_ctx returns a 16-byte aligned context pointer from `ctx`.
 struct aead_aes_gcm_siv_asm_ctx *asm_ctx_from_ctx(const EVP_AEAD_CTX *ctx) {
   // ctx->state must already be 8-byte aligned. Thus, at most, we may need to
@@ -656,7 +511,7 @@
     nullptr /* tag_len */,
 };
 
-#endif  // X86_64 && !NO_ASM && !WINDOWS
+#endif  // AES_GCM_SIV_ASM
 
 
 struct aead_aes_gcm_siv_ctx {
@@ -1044,28 +899,20 @@
 };
 }  // namespace
 
-#if defined(AES_GCM_SIV_ASM)
-
 const EVP_AEAD *EVP_aead_aes_128_gcm_siv() {
-  if (CRYPTO_is_AVX_capable() && CRYPTO_is_AESNI_capable() &&
-      CRYPTO_is_PCLMUL_capable()) {
+#if defined(AES_GCM_SIV_ASM)
+  if (aes_gcm_siv_asm_capable()) {
     return &aead_aes_128_gcm_siv_asm;
   }
+#endif
   return &aead_aes_128_gcm_siv;
 }
 
 const EVP_AEAD *EVP_aead_aes_256_gcm_siv() {
-  if (CRYPTO_is_AVX_capable() && CRYPTO_is_AESNI_capable() &&
-      CRYPTO_is_PCLMUL_capable()) {
+#if defined(AES_GCM_SIV_ASM)
+  if (aes_gcm_siv_asm_capable()) {
     return &aead_aes_256_gcm_siv_asm;
   }
+#endif
   return &aead_aes_256_gcm_siv;
 }
-
-#else
-
-const EVP_AEAD *EVP_aead_aes_128_gcm_siv() { return &aead_aes_128_gcm_siv; }
-
-const EVP_AEAD *EVP_aead_aes_256_gcm_siv() { return &aead_aes_256_gcm_siv; }
-
-#endif  // AES_GCM_SIV_ASM
diff --git a/crypto/cipher/internal.h b/crypto/cipher/internal.h
index 0293e34..8ee1c59 100644
--- a/crypto/cipher/internal.h
+++ b/crypto/cipher/internal.h
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <stdlib.h>
 
+#include <openssl/aead.h>
 #include <openssl/base.h>
 #include <openssl/sha.h>
 #include <openssl/span.h>
@@ -103,6 +104,9 @@
     bssl::Span<const uint8_t> trailer, size_t data_in_trailer_size,
     const uint8_t *mac_secret, unsigned mac_secret_length);
 
+
+// ChaCha20-Poly1305 Assembly.
+
 #define POLY1305_TAG_LEN 16
 
 // For convenience (the x86_64 calling convention allows only six parameters in
@@ -235,6 +239,161 @@
 }
 #endif
 
+
+// AES-GCM-SIV Assembly.
+
+// TODO(davidben): AES-GCM-SIV assembly is not correct for Windows. It must save
+// and restore xmm6 through xmm15.
+#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
+    !defined(OPENSSL_WINDOWS)
+#define AES_GCM_SIV_ASM
+
+struct aead_aes_gcm_siv_asm_ctx {
+  alignas(16) uint8_t key[16 * 15];
+  int is_128_bit;
+};
+
+inline int aes_gcm_siv_asm_capable() {
+  return CRYPTO_is_AVX_capable() && CRYPTO_is_AESNI_capable() &&
+         CRYPTO_is_PCLMUL_capable();
+}
+
+extern "C" {
+// aes128gcmsiv_aes_ks writes an AES-128 key schedule for `key` to
+// `out_expanded_key`. `out_expanded_key` must be 16-byte aligned.
+extern void aes128gcmsiv_aes_ks(const uint8_t key[16],
+                                uint8_t out_expanded_key[16 * 15]);
+
+// aes256gcmsiv_aes_ks writes an AES-256 key schedule for `key` to
+// `out_expanded_key`. `out_expanded_key` must be 16-byte aligned.
+extern void aes256gcmsiv_aes_ks(const uint8_t key[32],
+                                uint8_t out_expanded_key[16 * 15]);
+
+// aesgcmsiv_polyval_horner updates the POLYVAL value in `in_out_poly` to
+// include a number (`in_blocks`) of 16-byte blocks of data from `in`, given
+// the POLYVAL key in `key`. `in_out_poly` and `key` must be 16-byte aligned.
+extern void aesgcmsiv_polyval_horner(const uint8_t in_out_poly[16],
+                                     const uint8_t key[16], const uint8_t *in,
+                                     size_t in_blocks);
+
+// aesgcmsiv_htable_init writes powers 1..8 of `auth_key` to `out_htable`.
+// `out_htable` and `auth_key` must be 16-byte aligned.
+extern void aesgcmsiv_htable_init(uint8_t out_htable[16 * 8],
+                                  const uint8_t auth_key[16]);
+
+// aesgcmsiv_htable6_init writes powers 1..6 of `auth_key` to `out_htable`.
+// `out_htable` and `auth_key` must be 16-byte aligned.
+extern void aesgcmsiv_htable6_init(uint8_t out_htable[16 * 6],
+                                   const uint8_t auth_key[16]);
+
+// aesgcmsiv_htable_polyval updates the POLYVAL value in `in_out_poly` to
+// include `in_len` bytes of data from `in`. (Where `in_len` must be a multiple
+// of 16.) It uses the precomputed powers of the key given in `htable`.
+// `in_out_poly` and `htable` must be 16-byte aligned.
+extern void aesgcmsiv_htable_polyval(const uint8_t htable[16 * 8],
+                                     const uint8_t *in, size_t in_len,
+                                     uint8_t in_out_poly[16]);
+
+// aes128gcmsiv_dec decrypts `in_len` & ~15 bytes from `out` and writes them to
+// `in`. `in` and `out` may be equal, but must not otherwise alias.
+//
+// `in_out_calculated_tag_and_scratch`, on entry, must contain:
+//    1. The current value of the calculated tag, which will be updated during
+//       decryption and written back to the beginning of this buffer on exit.
+//    2. The claimed tag, which is needed to derive counter values.
+//
+// While decrypting, the whole of `in_out_calculated_tag_and_scratch` may be
+// used for other purposes. `in_out_calculated_tag_and_scratch` and `htable`
+// must be 16-byte aligned. In order to decrypt and update the POLYVAL value, it
+// uses the expanded key from `key` and the table of powers in `htable`.
+extern void aes128gcmsiv_dec(const uint8_t *in, uint8_t *out,
+                             uint8_t in_out_calculated_tag_and_scratch[16 * 8],
+                             const uint8_t htable[16 * 6],
+                             const struct aead_aes_gcm_siv_asm_ctx *key,
+                             size_t in_len);
+
+// aes256gcmsiv_dec acts like `aes128gcmsiv_dec`, but for AES-256.
+// `in_out_calculated_tag_and_scratch` and `htable` must be 16-byte aligned.
+extern void aes256gcmsiv_dec(const uint8_t *in, uint8_t *out,
+                             uint8_t in_out_calculated_tag_and_scratch[16 * 8],
+                             const uint8_t htable[16 * 6],
+                             const struct aead_aes_gcm_siv_asm_ctx *key,
+                             size_t in_len);
+
+// aes128gcmsiv_kdf performs the AES-GCM-SIV KDF given the expanded key from
+// `key_schedule` and the nonce in `nonce`. Note that, while only 12 bytes of
+// the nonce are used, 16 bytes are read and so the value must be
+// right-padded. `nonce`, `out_key_material`, and `key_schedule` must be
+// 16-byte aligned.
+extern void aes128gcmsiv_kdf(const uint8_t nonce[16],
+                             uint64_t out_key_material[8],
+                             const uint8_t *key_schedule);
+
+// aes256gcmsiv_kdf acts like `aes128gcmsiv_kdf`, but for AES-256. `nonce`,
+// `out_key_material`, and `key_schedule` must be 16-byte aligned.
+extern void aes256gcmsiv_kdf(const uint8_t nonce[16],
+                             uint64_t out_key_material[12],
+                             const uint8_t *key_schedule);
+
+// aes128gcmsiv_aes_ks_enc_x1 performs a key expansion of the AES-128 key in
+// `key`, writes the expanded key to `out_expanded_key` and encrypts a single
+// block from `in` to `out`. `in`, `out`, `out_expanded_key`, and `key` must be
+// 16-byte aligned.
+extern void aes128gcmsiv_aes_ks_enc_x1(const uint8_t in[16], uint8_t out[16],
+                                       uint8_t out_expanded_key[16 * 15],
+                                       const uint64_t key[2]);
+
+// aes256gcmsiv_aes_ks_enc_x1 acts like `aes128gcmsiv_aes_ks_enc_x1`, but for
+// AES-256. `in`, `out`, `out_expanded_key`, and `key` must be 16-byte aligned.
+extern void aes256gcmsiv_aes_ks_enc_x1(const uint8_t in[16], uint8_t out[16],
+                                       uint8_t out_expanded_key[16 * 15],
+                                       const uint64_t key[4]);
+
+// aes128gcmsiv_ecb_enc_block encrypts a single block from `in` to `out` using
+// the expanded key in `expanded_key`. `in` and `out` must be 16-byte aligned.
+extern void aes128gcmsiv_ecb_enc_block(
+    const uint8_t in[16], uint8_t out[16],
+    const struct aead_aes_gcm_siv_asm_ctx *expanded_key);
+
+// aes256gcmsiv_ecb_enc_block acts like `aes128gcmsiv_ecb_enc_block`, but for
+// AES-256. `in` and `out` must be 16-byte aligned.
+extern void aes256gcmsiv_ecb_enc_block(
+    const uint8_t in[16], uint8_t out[16],
+    const struct aead_aes_gcm_siv_asm_ctx *expanded_key);
+
+// aes128gcmsiv_enc_msg_x4 encrypts `in_len` bytes from `in` to `out` using the
+// expanded key from `key`. (The value of `in_len` must be a multiple of 16.)
+// The `in` and `out` buffers may be equal but must not otherwise overlap. The
+// initial counter is constructed from the given `tag` as required by
+// AES-GCM-SIV. `tag` must be 16-byte aligned.
+extern void aes128gcmsiv_enc_msg_x4(const uint8_t *in, uint8_t *out,
+                                    const uint8_t *tag,
+                                    const struct aead_aes_gcm_siv_asm_ctx *key,
+                                    size_t in_len);
+
+// aes256gcmsiv_enc_msg_x4 acts like `aes128gcmsiv_enc_msg_x4`, but for
+// AES-256. `tag` must be 16-byte aligned.
+extern void aes256gcmsiv_enc_msg_x4(const uint8_t *in, uint8_t *out,
+                                    const uint8_t *tag,
+                                    const struct aead_aes_gcm_siv_asm_ctx *key,
+                                    size_t in_len);
+
+// aes128gcmsiv_enc_msg_x8 acts like `aes128gcmsiv_enc_msg_x4`, but is
+// optimised for longer messages.
+extern void aes128gcmsiv_enc_msg_x8(const uint8_t *in, uint8_t *out,
+                                    const uint8_t *tag,
+                                    const struct aead_aes_gcm_siv_asm_ctx *key,
+                                    size_t in_len);
+
+// aes256gcmsiv_enc_msg_x8 acts like `aes256gcmsiv_enc_msg_x4`, but is
+// optimised for longer messages.
+extern void aes256gcmsiv_enc_msg_x8(const uint8_t *in, uint8_t *out,
+                                    const uint8_t *tag,
+                                    const struct aead_aes_gcm_siv_asm_ctx *key,
+                                    size_t in_len);
+}
+#endif  // OPENSSL_X86_64 && !OPENSSL_NO_ASM && !OPENSSL_WINDOWS
+
 BSSL_NAMESPACE_END
 
 #endif  // OPENSSL_HEADER_CRYPTO_CIPHER_INTERNAL_H