Skip to content

Instantly share code, notes, and snippets.

@aalness
Last active March 10, 2023 10:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aalness/577c7a6da1e669a07db9 to your computer and use it in GitHub Desktop.
Save aalness/577c7a6da1e669a07db9 to your computer and use it in GitHub Desktop.
Benchmark SHA256 for libsecp256k1 / crypto++ / openssl
#include <string.h>
#include <sys/time.h>
#include <iostream>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include "secp256k1/src/hash_impl.h"
#include "cryptopp/sha.h"
static const size_t NUM_RUNS = 300000UL;
static double msecs(void)
{
struct timeval te;
gettimeofday(&te, NULL);
double msecs = te.tv_sec*1000.0 + te.tv_usec/1000.0;
return msecs;
}
static void openssl(const std::string& message, unsigned char* out)
{
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, message.c_str(), message.length());
SHA256_Final(out, &sha256);
}
static void cryptopp(const std::string& message, unsigned char* out)
{
CryptoPP::SHA256 hash;
hash.Update((const byte*)message.c_str(), message.length());
hash.Final(out);
}
static void secp256k1(const std::string& message, unsigned char* out)
{
secp256k1_sha256_t hasher;
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)message.c_str(), message.length());
secp256k1_sha256_finalize(&hasher, out);
}
int main(int ac, char *av[])
{
if (ac != 2)
{
std::cout << "usage: " << av[0] << " <message size>" << std::endl;
return 1;
}
const size_t size = strtoul(av[1], 0, 0);
assert(size);
std::cout << "size: " << size << ", num runs: " << NUM_RUNS << std::endl;
// test correctness
for (size_t i = 0; i < 1000; ++i)
{
std::string message;
message.resize(size);
assert(RAND_bytes((unsigned char*)&message[0], size) == 1);
unsigned char out[32], out2[32], out3[32];
openssl(message, out);
cryptopp(message, out2);
secp256k1(message, out3);
assert(!memcmp(out, out2, 32));
assert(!memcmp(out, out3, 32));
}
std::string message;
message.resize(size);
assert(RAND_bytes((unsigned char*)&message[0], size) == 1);
double before, after;
before = msecs();
for (size_t i = 0; i < NUM_RUNS; ++i)
{
unsigned char out[32];
cryptopp(message, out);
}
after = msecs();
std::cout << " cryptopp took: " << (after-before) << "ms" << std::endl;
before = msecs();
for (size_t i = 0; i < NUM_RUNS; ++i)
{
unsigned char out[32];
openssl(message, out);
}
after = msecs();
std::cout << " openssl took: " << (after-before) << "ms" << std::endl;
before = msecs();
for (size_t i = 0; i < NUM_RUNS; ++i)
{
unsigned char out[32];
secp256k1(message, out);
}
after = msecs();
std::cout << "libsecp256k1 took: " << (after-before) << "ms" << std::endl;
return 0;
}
@aalness
Copy link
Author

aalness commented Dec 13, 2014

A few runs:


andy@lab:~$ ./benchmark 32
size: 32
     openssl low: 1 hi: 429 avg: 1
    cryptopp low: 2 hi: 191 avg: 2
libsecp256k1 low: 2 hi: 84 avg: 2
andy@lab:~$ ./benchmark 256
size: 256
     openssl low: 3 hi: 159 avg: 3
    cryptopp low: 4 hi: 77 avg: 4
libsecp256k1 low: 6 hi: 244 avg: 6
andy@lab:~$ ./benchmark 2048
size: 2048
     openssl low: 15 hi: 556 avg: 16
    cryptopp low: 17 hi: 876 avg: 18
libsecp256k1 low: 35 hi: 471 avg: 36
andy@lab:~$ ./benchmark 8192
size: 8192
     openssl low: 58 hi: 1861 avg: 60
    cryptopp low: 63 hi: 928 avg: 65
libsecp256k1 low: 134 hi: 923 avg: 137

The openssl numbers seem roughly consistent w/openssl speed sha256

@sipa
Copy link

sipa commented Dec 14, 2014

Interesting. Perhaps it's more relevant to do many full cycles (initialize + write short message + finalize), as that is the use case in libsecp256k1 - not large amounts of data.

@aalness
Copy link
Author

aalness commented Dec 14, 2014

Yup. Had a similar thought but the numbers still work out the same. Code updated. I verified that at least with the cryptopp code it is using the ASM version of SHA256 transform.


andy@lab:~$ ./benchmark 32
size: 32, num runs: 300000
    cryptopp took: 286.192ms
     openssl took: 162.157ms
libsecp256k1 took: 352.647ms
andy@lab:~$ ./benchmark 256
size: 256, num runs: 300000
    cryptopp took: 900.827ms
     openssl took: 697.887ms
libsecp256k1 took: 1616.3ms
andy@lab:~$ ./benchmark 2048
size: 2048, num runs: 300000
    cryptopp took: 5015.51ms
     openssl took: 4536.79ms
libsecp256k1 took: 10477.9ms
andy@lab:~$ ./benchmark 8192
size: 8192, num runs: 300000
    cryptopp took: 19195ms
     openssl took: 17554.8ms
libsecp256k1 took: 40710.7ms

@aalness
Copy link
Author

aalness commented Dec 14, 2014

I don't think these #s are particularly damning or anything. For the normal workload of libsecp256k1 (on order of 32 bytes) it is perfectly fine. At least it would be remarkable if the difference mattered but we'd have much bigger problems to deal with in that case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment