Add bssl speed support for hashtocurve and trusttoken.

Change-Id: I74bee1855c593131bf1451553de6a56b4e0e8a54
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/40804
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/trust_token/internal.h b/crypto/trust_token/internal.h
index 6edd111..3154077 100644
--- a/crypto/trust_token/internal.h
+++ b/crypto/trust_token/internal.h
@@ -25,6 +25,11 @@
 #include <openssl/trust_token.h>
 
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
 // PMBTokens is described in https://eprint.iacr.org/2020/072/20200324:214215
 // and provides anonymous tokens with private metadata. We implement the
 // construction with validity verification, described in appendix H,
@@ -67,7 +72,7 @@
 } PMBTOKEN_PRETOKEN;
 
 // PMBTOKEN_PRETOKEN_free releases the memory associated with |token|.
-void PMBTOKEN_PRETOKEN_free(PMBTOKEN_PRETOKEN *token);
+OPENSSL_EXPORT void PMBTOKEN_PRETOKEN_free(PMBTOKEN_PRETOKEN *token);
 
 DEFINE_STACK_OF(PMBTOKEN_PRETOKEN)
 
@@ -162,4 +167,19 @@
   size_t metadata_key_len;
 };
 
+
+#if defined(__cplusplus)
+}  // extern C
+
+extern "C++" {
+
+BSSL_NAMESPACE_BEGIN
+
+BORINGSSL_MAKE_DELETER(PMBTOKEN_PRETOKEN, PMBTOKEN_PRETOKEN_free)
+
+BSSL_NAMESPACE_END
+
+}  // extern C++
+#endif
+
 #endif  // OPENSSL_HEADER_TRUST_TOKEN_INTERNAL_H
diff --git a/tool/speed.cc b/tool/speed.cc
index 224a72b..b87afb9 100644
--- a/tool/speed.cc
+++ b/tool/speed.cc
@@ -35,9 +35,11 @@
 #include <openssl/ec_key.h>
 #include <openssl/evp.h>
 #include <openssl/hrss.h>
+#include <openssl/mem.h>
 #include <openssl/nid.h>
 #include <openssl/rand.h>
 #include <openssl/rsa.h>
+#include <openssl/trust_token.h>
 
 #if defined(OPENSSL_WINDOWS)
 OPENSSL_MSVC_PRAGMA(warning(push, 3))
@@ -49,7 +51,10 @@
 #include <time.h>
 #endif
 
+#include "../crypto/ec_extra/internal.h"
+#include "../crypto/fipsmodule/ec/internal.h"
 #include "../crypto/internal.h"
+#include "../crypto/trust_token/internal.h"
 #include "internal.h"
 
 // g_print_json is true if printed output is JSON formatted.
@@ -942,6 +947,279 @@
   return true;
 }
 
+static bool SpeedHashToCurve(const std::string &selected) {
+  if (!selected.empty() && selected.find("hashtocurve") == std::string::npos) {
+    return true;
+  }
+
+  EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1);
+  if (group == NULL) {
+    return false;
+  }
+  uint8_t input[64];
+  RAND_bytes(input, sizeof(input));
+
+  static const uint8_t kLabel[] = "label";
+
+  TimeResults results;
+  if (!TimeFunction(&results, [&]() -> bool {
+        EC_RAW_POINT out;
+        return ec_hash_to_curve_p521_xmd_sha512_sswu(
+            group, &out, kLabel, sizeof(kLabel), input, sizeof(input));
+      })) {
+    fprintf(stderr, "hash-to-curve failed.\n");
+    return false;
+  }
+  results.Print("hash-to-curve P521_XMD:SHA-512_SSWU_RO_");
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        EC_SCALAR out;
+        return ec_hash_to_scalar_p521_xmd_sha512(
+            group, &out, kLabel, sizeof(kLabel), input, sizeof(input));
+      })) {
+    fprintf(stderr, "hash-to-scalar failed.\n");
+    return false;
+  }
+  results.Print("hash-to-scalar P521_XMD:SHA-512");
+
+  return true;
+}
+
+static PMBTOKEN_PRETOKEN *pmbtoken_pretoken_dup(PMBTOKEN_PRETOKEN *in) {
+  PMBTOKEN_PRETOKEN *out =
+      (PMBTOKEN_PRETOKEN *)OPENSSL_malloc(sizeof(PMBTOKEN_PRETOKEN));
+  if (out) {
+    OPENSSL_memcpy(out, in, sizeof(PMBTOKEN_PRETOKEN));
+  }
+  return out;
+}
+
+static bool SpeedTrustToken(std::string name, size_t batchsize,
+                            const std::string &selected) {
+  if (!selected.empty() && selected.find("trusttoken") == std::string::npos) {
+    return true;
+  }
+
+  TimeResults results;
+  if (!TimeFunction(&results, [&]() -> bool {
+        uint8_t priv_key[TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE];
+        uint8_t pub_key[TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE];
+        size_t priv_key_len, pub_key_len;
+        return TRUST_TOKEN_generate_key(
+            priv_key, &priv_key_len, TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE, pub_key,
+            &pub_key_len, TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0);
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_generate_key failed.\n");
+    return false;
+  }
+  results.Print(name + " generate_key");
+
+  bssl::UniquePtr<TRUST_TOKEN_CLIENT> client(TRUST_TOKEN_CLIENT_new(batchsize));
+  bssl::UniquePtr<TRUST_TOKEN_ISSUER> issuer(TRUST_TOKEN_ISSUER_new(batchsize));
+  uint8_t priv_key[TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE];
+  uint8_t pub_key[TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE];
+  size_t priv_key_len, pub_key_len, key_index;
+  if (!client ||
+      !issuer ||
+      !TRUST_TOKEN_generate_key(
+          priv_key, &priv_key_len, TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE, pub_key,
+          &pub_key_len, TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0) ||
+      !TRUST_TOKEN_CLIENT_add_key(client.get(), &key_index, pub_key,
+                                  pub_key_len) ||
+      !TRUST_TOKEN_ISSUER_add_key(issuer.get(), priv_key, priv_key_len)) {
+    fprintf(stderr, "failed to generate trust token key.\n");
+    return false;
+  }
+
+  uint8_t public_key[32], private_key[64];
+  ED25519_keypair(public_key, private_key);
+  bssl::UniquePtr<EVP_PKEY> priv(
+      EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, nullptr, private_key, 32));
+  bssl::UniquePtr<EVP_PKEY> pub(
+      EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, nullptr, public_key, 32));
+  if (!priv || !pub) {
+    fprintf(stderr, "failed to generate trust token SRR key.\n");
+    return false;
+  }
+
+  TRUST_TOKEN_CLIENT_set_srr_key(client.get(), pub.get());
+  TRUST_TOKEN_ISSUER_set_srr_key(issuer.get(), priv.get());
+  uint8_t metadata_key[32];
+  RAND_bytes(metadata_key, sizeof(metadata_key));
+  if (!TRUST_TOKEN_ISSUER_set_metadata_key(issuer.get(), metadata_key,
+                                           sizeof(metadata_key))) {
+    fprintf(stderr, "failed to generate trust token metadata key.\n");
+    return false;
+  }
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        uint8_t *issue_msg = NULL;
+        size_t msg_len;
+        int ok = TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+                                                   &msg_len, batchsize);
+        OPENSSL_free(issue_msg);
+        // Clear pretokens.
+        sk_PMBTOKEN_PRETOKEN_pop_free(client->pretokens,
+                                      PMBTOKEN_PRETOKEN_free);
+        client->pretokens = sk_PMBTOKEN_PRETOKEN_new_null();
+        return ok;
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_issuance failed.\n");
+    return false;
+  }
+  results.Print(name + " begin_issuance");
+
+  uint8_t *issue_msg = NULL;
+  size_t msg_len;
+  if (!TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg, &msg_len,
+                                         batchsize)) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_issuance failed.\n");
+    return false;
+  }
+  bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
+
+  bssl::UniquePtr<STACK_OF(PMBTOKEN_PRETOKEN)> pretokens(
+      sk_PMBTOKEN_PRETOKEN_deep_copy(client->pretokens, pmbtoken_pretoken_dup,
+                                     PMBTOKEN_PRETOKEN_free));
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        uint8_t *issue_resp = NULL;
+        size_t resp_len;
+        uint8_t tokens_issued;
+        int ok = TRUST_TOKEN_ISSUER_issue(issuer.get(), &issue_resp, &resp_len,
+                                          &tokens_issued, issue_msg, msg_len,
+                                          /*public_metadata=*/0,
+                                          /*private_metadata=*/0,
+                                          /*max_issuance=*/batchsize);
+        OPENSSL_free(issue_resp);
+        return ok;
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_ISSUER_issue failed.\n");
+    return false;
+  }
+  results.Print(name + " issue");
+
+  uint8_t *issue_resp = NULL;
+  size_t resp_len;
+  uint8_t tokens_issued;
+  if (!TRUST_TOKEN_ISSUER_issue(issuer.get(), &issue_resp, &resp_len,
+                                &tokens_issued, issue_msg, msg_len,
+                                /*public_metadata=*/0, /*private_metadata=*/0,
+                                /*max_issuance=*/batchsize)) {
+    fprintf(stderr, "TRUST_TOKEN_ISSUER_issue failed.\n");
+    return false;
+  }
+  bssl::UniquePtr<uint8_t> free_issue_resp(issue_resp);
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        size_t key_index2;
+        bssl::UniquePtr<STACK_OF(TRUST_TOKEN)> tokens(
+            TRUST_TOKEN_CLIENT_finish_issuance(client.get(), &key_index2,
+                                               issue_resp, resp_len));
+
+        // Reset pretokens.
+        client->pretokens = sk_PMBTOKEN_PRETOKEN_deep_copy(
+            pretokens.get(), pmbtoken_pretoken_dup, PMBTOKEN_PRETOKEN_free);
+        return !!tokens;
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_finish_issuance failed.\n");
+    return false;
+  }
+  results.Print(name + " finish_issuance");
+
+  bssl::UniquePtr<STACK_OF(TRUST_TOKEN)> tokens(
+      TRUST_TOKEN_CLIENT_finish_issuance(client.get(), &key_index, issue_resp,
+                                         resp_len));
+  if (!tokens || sk_TRUST_TOKEN_num(tokens.get()) < 1) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_finish_issuance failed.\n");
+    return false;
+  }
+
+  const TRUST_TOKEN *token = sk_TRUST_TOKEN_value(tokens.get(), 0);
+
+  const uint8_t kClientData[] = "\x70TEST CLIENT DATA";
+  uint64_t kRedemptionTime = 13374242;
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        uint8_t *redeem_msg = NULL;
+        size_t redeem_msg_len;
+        int ok = TRUST_TOKEN_CLIENT_begin_redemption(
+            client.get(), &redeem_msg, &redeem_msg_len, token, kClientData,
+            sizeof(kClientData) - 1, kRedemptionTime);
+        OPENSSL_free(redeem_msg);
+        return ok;
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_redemption failed.\n");
+    return false;
+  }
+  results.Print(name + " begin_redemption");
+
+  uint8_t *redeem_msg = NULL;
+  size_t redeem_msg_len;
+  if (!TRUST_TOKEN_CLIENT_begin_redemption(
+          client.get(), &redeem_msg, &redeem_msg_len, token, kClientData,
+          sizeof(kClientData) - 1, kRedemptionTime)) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_redemption failed.\n");
+    return false;
+  }
+  bssl::UniquePtr<uint8_t> free_redeem_msg(redeem_msg);
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        uint8_t *redeem_resp = NULL;
+        size_t redeem_resp_len;
+        TRUST_TOKEN *rtoken = NULL;
+        uint8_t *client_data = NULL;
+        size_t client_data_len;
+        uint64_t redemption_time;
+        int ok = TRUST_TOKEN_ISSUER_redeem(
+            issuer.get(), &redeem_resp, &redeem_resp_len, &rtoken, &client_data,
+            &client_data_len, &redemption_time, redeem_msg, redeem_msg_len,
+            /*lifetime=*/600);
+        OPENSSL_free(redeem_resp);
+        OPENSSL_free(client_data);
+        TRUST_TOKEN_free(rtoken);
+        return ok;
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_ISSUER_redeem failed.\n");
+    return false;
+  }
+  results.Print(name + " redeem");
+
+  uint8_t *redeem_resp = NULL;
+  size_t redeem_resp_len;
+  TRUST_TOKEN *rtoken = NULL;
+  uint8_t *client_data = NULL;
+  size_t client_data_len;
+  uint64_t redemption_time;
+  if (!TRUST_TOKEN_ISSUER_redeem(issuer.get(), &redeem_resp, &redeem_resp_len,
+                                 &rtoken, &client_data, &client_data_len,
+                                 &redemption_time, redeem_msg, redeem_msg_len,
+                                 /*lifetime=*/600)) {
+    fprintf(stderr, "TRUST_TOKEN_ISSUER_redeem failed.\n");
+    return false;
+  }
+  bssl::UniquePtr<uint8_t> free_redeem_resp(redeem_resp);
+  bssl::UniquePtr<uint8_t> free_client_data(client_data);
+  bssl::UniquePtr<TRUST_TOKEN> free_rtoken(rtoken);
+
+  if (!TimeFunction(&results, [&]() -> bool {
+        uint8_t *srr = NULL, *sig = NULL;
+        size_t srr_len, sig_len;
+        int ok = TRUST_TOKEN_CLIENT_finish_redemption(client.get(), &srr,
+                                                      &srr_len, &sig, &sig_len,
+                                                      redeem_resp, resp_len);
+        OPENSSL_free(srr);
+        OPENSSL_free(sig);
+        return ok;
+      })) {
+    fprintf(stderr, "TRUST_TOKEN_CLIENT_finish_redemption failed.\n");
+    return false;
+  }
+  results.Print(name + " finish_redemption");
+
+  return true;
+}
+
 static const struct argument kArguments[] = {
     {
         "-filter",
@@ -1071,7 +1349,10 @@
       !SpeedSPAKE2(selected) ||
       !SpeedScrypt(selected) ||
       !SpeedRSAKeyGen(selected) ||
-      !SpeedHRSS(selected)) {
+      !SpeedHRSS(selected) ||
+      !SpeedHashToCurve(selected) ||
+      !SpeedTrustToken("TrustToken-Batch1", 1, selected) ||
+      !SpeedTrustToken("TrustToken-Batch10", 10, selected)) {
     return false;
   }
   if (g_print_json) {