Revise the deterministic for_test variant of HPKE's SetupBaseS.

Although we only support X25519 right now, we may need to support other
KEMs in the future. In the general case, a public/private keypair is
less meaningful. (If something like NTRU-HRSS even goes here, I guess
it'd be the entropy passed to HRSS_encap.)

Instead of taking an entire keypair, just take the private key. Perhaps
we call it the "seed"?

Bug: 410
Change-Id: Ifd6b6ea8ea36e6eca60d303706d6d2620f8c42d4
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47326
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c
index f6aca0f..cc0def5 100644
--- a/crypto/hpke/hpke.c
+++ b/crypto/hpke/hpke.c
@@ -22,6 +22,7 @@
 #include <openssl/err.h>
 #include <openssl/evp_errors.h>
 #include <openssl/hkdf.h>
+#include <openssl/rand.h>
 #include <openssl/sha.h>
 
 #include "../internal.h"
@@ -304,34 +305,27 @@
                                      const uint8_t *peer_public_value,
                                      size_t peer_public_value_len,
                                      const uint8_t *info, size_t info_len) {
+  uint8_t seed[X25519_PRIVATE_KEY_LEN];
+  RAND_bytes(seed, sizeof(seed));
+  return EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+      hpke, out_enc, out_enc_len, kdf_id, aead_id, peer_public_value,
+      peer_public_value_len, info, info_len, seed, sizeof(seed));
+}
+
+int EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+    EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, uint16_t kdf_id,
+    uint16_t aead_id, const uint8_t *peer_public_value,
+    size_t peer_public_value_len, const uint8_t *info, size_t info_len,
+    const uint8_t *seed, size_t seed_len) {
   if (out_enc_len != X25519_PUBLIC_VALUE_LEN) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_BUFFER_SIZE);
     return 0;
   }
-
-  // The GenerateKeyPair() step technically belongs in the KEM's Encap()
-  // function, but we've moved it up a layer to make it easier for tests to
-  // inject an ephemeral keypair.
-  uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
-  X25519_keypair(out_enc, ephemeral_private);
-  return EVP_HPKE_CTX_setup_base_s_x25519_for_test(
-      hpke, kdf_id, aead_id, peer_public_value, peer_public_value_len, info,
-      info_len, ephemeral_private, sizeof(ephemeral_private), out_enc,
-      out_enc_len);
-}
-
-int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
-    EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
-    const uint8_t *peer_public_value, size_t peer_public_value_len,
-    const uint8_t *info, size_t info_len, const uint8_t *ephemeral_private,
-    size_t ephemeral_private_len, const uint8_t *ephemeral_public,
-    size_t ephemeral_public_len) {
   if (peer_public_value_len != X25519_PUBLIC_VALUE_LEN) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
     return 0;
   }
-  if (ephemeral_private_len != X25519_PRIVATE_KEY_LEN ||
-      ephemeral_public_len != X25519_PUBLIC_VALUE_LEN) {
+  if (seed_len != X25519_PRIVATE_KEY_LEN) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return 0;
   }
@@ -343,9 +337,9 @@
   if (hpke->hkdf_md == NULL) {
     return 0;
   }
+  X25519_public_from_private(out_enc, seed);
   uint8_t shared_secret[SHA256_DIGEST_LENGTH];
-  if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
-                  ephemeral_public) ||
+  if (!hpke_encap(hpke, shared_secret, peer_public_value, seed, out_enc) ||
       !hpke_key_schedule(hpke, shared_secret, sizeof(shared_secret), info,
                          info_len)) {
     return 0;
diff --git a/crypto/hpke/hpke_test.cc b/crypto/hpke/hpke_test.cc
index 5b063a3..e4aa932 100644
--- a/crypto/hpke/hpke_test.cc
+++ b/crypto/hpke/hpke_test.cc
@@ -51,17 +51,18 @@
     ASSERT_GT(secret_key_e_.size(), 0u);
 
     // Set up the sender.
-    ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_for_test(
-        sender_ctx.get(), kdf_id_, aead_id_, public_key_r_.data(),
-        public_key_r_.size(), info_.data(), info_.size(), secret_key_e_.data(),
-        secret_key_e_.size(), public_key_e_.data(), public_key_e_.size()));
+    uint8_t enc[X25519_PUBLIC_VALUE_LEN];
+    ASSERT_TRUE(EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+        sender_ctx.get(), enc, sizeof(enc), kdf_id_, aead_id_,
+        public_key_r_.data(), public_key_r_.size(), info_.data(), info_.size(),
+        secret_key_e_.data(), secret_key_e_.size()));
+    EXPECT_EQ(Bytes(enc), Bytes(public_key_e_));
 
     // Set up the receiver.
     ASSERT_TRUE(EVP_HPKE_CTX_setup_base_r_x25519(
-        receiver_ctx.get(), kdf_id_, aead_id_, public_key_e_.data(),
-        public_key_e_.size(), public_key_r_.data(), public_key_r_.size(),
-        secret_key_r_.data(), secret_key_r_.size(), info_.data(),
-        info_.size()));
+        receiver_ctx.get(), kdf_id_, aead_id_, enc, sizeof(enc),
+        public_key_r_.data(), public_key_r_.size(), secret_key_r_.data(),
+        secret_key_r_.size(), info_.data(), info_.size()));
 
     VerifyEncryptions(sender_ctx.get(), receiver_ctx.get());
     VerifyExports(sender_ctx.get());
diff --git a/crypto/hpke/internal.h b/crypto/hpke/internal.h
index cda9b7a..54382c8 100644
--- a/crypto/hpke/internal.h
+++ b/crypto/hpke/internal.h
@@ -94,16 +94,14 @@
     uint16_t aead_id, const uint8_t *peer_public_value,
     size_t peer_public_value_len, const uint8_t *info, size_t info_len);
 
-// EVP_HPKE_CTX_setup_base_s_x25519_for_test behaves like
-// |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a pre-generated ephemeral
-// sender key. The caller ensures that |ephemeral_public| and
-// |ephemeral_private| are a valid keypair.
-OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
-    EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
-    const uint8_t *peer_public_value, size_t peer_public_value_len,
-    const uint8_t *info, size_t info_len, const uint8_t *ephemeral_private,
-    size_t ephemeral_private_len, const uint8_t *ephemeral_public,
-    size_t ephemeral_public_len);
+// EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing behaves like
+// |EVP_HPKE_CTX_setup_base_s_x25519|, but takes a seed value to behave
+// deterministically. This seed is the sender's ephemeral X25519 key.
+OPENSSL_EXPORT int EVP_HPKE_CTX_setup_base_s_x25519_with_seed_for_testing(
+    EVP_HPKE_CTX *hpke, uint8_t *out_enc, size_t out_enc_len, uint16_t kdf_id,
+    uint16_t aead_id, const uint8_t *peer_public_value,
+    size_t peer_public_value_len, const uint8_t *info, size_t info_len,
+    const uint8_t *seed, size_t seed_len);
 
 // EVP_HPKE_CTX_setup_base_r_x25519 sets up |hpke| as a recipient context that
 // can decrypt messages. It returns one on success, and zero otherwise.