Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DH_check support to perf tool #982

Merged
merged 4 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tool/bssl_bm.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "openssl/ctrdrbg.h"
#include <openssl/curve25519.h>
#include <openssl/crypto.h>
#include <openssl/dh.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/ec.h>
Expand Down
2 changes: 2 additions & 0 deletions tool/ossl_bm.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <openssl/aes.h>
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/dh.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
Expand Down Expand Up @@ -53,6 +54,7 @@ template <typename T> struct Deleter {
} // namespace internal
template <typename T> using UniquePtr = std::unique_ptr<T, internal::Deleter<T>>;

OSSL_MAKE_DELETER(DH, DH_free)
OSSL_MAKE_DELETER(RSA, RSA_free)
OSSL_MAKE_DELETER(BIGNUM, BN_free)
OSSL_MAKE_DELETER(EC_KEY, EC_KEY_free)
Expand Down
166 changes: 142 additions & 24 deletions tool/speed.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ static std::string ChunkLenSuffix(size_t chunk_len) {
return buf;
}

static std::string PrimeLenSuffix(size_t prime_length) {
char buf[32];
snprintf(buf, sizeof(buf), " (%zu bit%s)", prime_length,
prime_length != 1 ? "s" : "");
return buf;
}

// TimeResults represents the results of benchmarking a function.
struct TimeResults {
// num_calls is the number of function calls done in the time period.
Expand Down Expand Up @@ -113,6 +120,19 @@ struct TimeResults {
}
}

void PrintWithPrimes(const std::string &description,
torben-hansen marked this conversation as resolved.
Show resolved Hide resolved
size_t prime_size) const {
if (g_print_json) {
PrintJSON(description, "primeSizePerCall", prime_size);
} else {
printf(
"Did %" PRIu64 " %s operations in %" PRIu64
"us (%.3f ops/sec)\n",
num_calls, (description + PrimeLenSuffix(prime_size)).c_str(), us,
(static_cast<double>(num_calls) / static_cast<double>(us)) * 1000000);
}
}

private:
void PrintJSON(const std::string &description,
size_t bytes_per_call = 0) const {
Expand All @@ -132,6 +152,25 @@ struct TimeResults {
first_json_printed = true;
}

void PrintJSON(const std::string &description,
const std::string &size_label,
size_t size = 0) const {
if (first_json_printed) {
puts(",");
}

printf("{\"description\": \"%s\", \"numCalls\": %" PRIu64
", \"microseconds\": %" PRIu64,
description.c_str(), num_calls, us);

if (size > 0) {
printf(", \"%s\": %zu", size_label.c_str(), size);
}

printf("}");
first_json_printed = true;
}

// first_json_printed is true if |g_print_json| is true and the first item in
// the JSON results has been printed already. This is used to handle the
// commas between each item in the result list.
Expand Down Expand Up @@ -165,8 +204,10 @@ static uint64_t time_now() {
}
#endif

static uint64_t g_timeout_seconds = 1;
#define TIMEOUT_SECONDS_DEFAULT 1
static uint64_t g_timeout_seconds = TIMEOUT_SECONDS_DEFAULT;
static std::vector<size_t> g_chunk_lengths = {16, 256, 1350, 8192, 16384};
static std::vector<size_t> g_prime_bit_lengths = {2048, 3072};

static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
// The first time |func| is called an expensive self check might run that
Expand Down Expand Up @@ -1944,6 +1985,56 @@ static bool SpeedJitter(std::string selected) {
}
#endif

static bool SpeedDHcheck(size_t prime_bit_length) {

TimeResults results;
BM_NAMESPACE::UniquePtr<DH> dh_params(DH_new());
if (dh_params == nullptr) {
return false;
}

// DH_generate_parameters_ex grows exponentially slower as prime length grows.
if (DH_generate_parameters_ex(dh_params.get(), prime_bit_length,
andrewhop marked this conversation as resolved.
Show resolved Hide resolved
DH_GENERATOR_2, nullptr) != 1) {
return false;
}

if (!TimeFunction(&results, [&dh_params]() -> bool {
int result = 0;
if (DH_check(dh_params.get(), &result) != 1) {
return false;
}
return true;
})) {
return false;
}

results.PrintWithPrimes("DH check(s)", prime_bit_length);
return true;
}

static bool SpeedDHcheck(std::string selected) {
// Don't run this by default because it's so slow.
if (selected != "dhcheck") {
return true;
}

uint64_t maybe_reset_timeout = g_timeout_seconds;
if (g_timeout_seconds == TIMEOUT_SECONDS_DEFAULT) {
g_timeout_seconds = 10;
}

for (size_t prime_bit_length : g_prime_bit_lengths) {
if (!SpeedDHcheck(prime_bit_length)) {
return false;
}
}

g_timeout_seconds = maybe_reset_timeout;

return true;
}

#if !defined(OPENSSL_BENCHMARK) && !defined(BORINGSSL_BENCHMARK)
static bool SpeedPKCS8(const std::string &selected) {
if (!selected.empty() && selected.find("pkcs8") == std::string::npos) {
Expand Down Expand Up @@ -2056,6 +2147,12 @@ static const argument_t kArguments[] = {
"A comma-separated list of input sizes to run tests at (default is "
"16,256,1350,8192,16384)",
},
{
"-primes",
torben-hansen marked this conversation as resolved.
Show resolved Hide resolved
kOptionalArgument,
"A comma-separated list of prime input sizes (bits) to run tests at "
"(default is 2048,3072)",
},
{
"-json",
kBooleanArgument,
Expand All @@ -2073,6 +2170,38 @@ static const argument_t kArguments[] = {
},
};

// parseCommaArgumentToGlobalVector clears |vector| and parses comma-separated
// input for the argument |arg_name| in |args_map|.
static bool parseCommaArgumentToGlobalVector(std::vector<size_t> &vector,
std::map<std::string, std::string> &args_map, const std::string &arg_name) {

vector.clear();
const char *start = args_map[arg_name.c_str()].data();
const char *end = start + args_map[arg_name.c_str()].size();
while (start != end) {
errno = 0;
char *ptr;
unsigned long long val = strtoull(start, &ptr, 10);
if (ptr == start /* no numeric characters found */ ||
errno == ERANGE /* overflow */ ||
static_cast<size_t>(val) != val) {
fprintf(stderr, "Error parsing %s argument\n", arg_name.c_str());
return false;
}
vector.push_back(static_cast<size_t>(val));
start = ptr;
if (start != end) {
if (*start != ',') {
fprintf(stderr, "Error parsing %s argument\n", arg_name.c_str());
return false;
}
start++;
}
}

return true;
}

bool Speed(const std::vector<std::string> &args) {
#if defined(OPENSSL_IS_AWSLC)
// For mainline AWS-LC this is a no-op, however if speed.cc built with an old
Expand All @@ -2099,28 +2228,16 @@ bool Speed(const std::vector<std::string> &args) {
}

if (args_map.count("-chunks") != 0) {
g_chunk_lengths.clear();
const char *start = args_map["-chunks"].data();
const char *end = start + args_map["-chunks"].size();
while (start != end) {
errno = 0;
char *ptr;
unsigned long long val = strtoull(start, &ptr, 10);
if (ptr == start /* no numeric characters found */ ||
errno == ERANGE /* overflow */ ||
static_cast<size_t>(val) != val) {
fprintf(stderr, "Error parsing -chunks argument\n");
return false;
}
g_chunk_lengths.push_back(static_cast<size_t>(val));
start = ptr;
if (start != end) {
if (*start != ',') {
fprintf(stderr, "Error parsing -chunks argument\n");
return false;
}
start++;
}
if (!parseCommaArgumentToGlobalVector(g_chunk_lengths,
args_map, "-chunks")) {
return false;
}
}

if (args_map.count("-primes") != 0) {
torben-hansen marked this conversation as resolved.
Show resolved Hide resolved
if (!parseCommaArgumentToGlobalVector(g_prime_bit_lengths,
args_map, "-primes")) {
return false;
}
}

Expand Down Expand Up @@ -2187,7 +2304,8 @@ bool Speed(const std::vector<std::string> &args) {
!SpeedScrypt(selected) ||
#endif
!SpeedRSA(selected) ||
!SpeedRSAKeyGen(false, selected)
!SpeedRSAKeyGen(false, selected) ||
!SpeedDHcheck(selected)
#if !defined(OPENSSL_BENCHMARK)
||
!SpeedKEM(selected) ||
Expand Down