mirror of
https://github.com/shadps4-emu/ext-cryptopp.git
synced 2024-12-02 15:36:25 +00:00
f290746a36
Use std::ostringstream instead. Eventually I'd like to see the output stream passed into the function of interest. It will avoid problems on some mobile OSes that don't have standard inputs and outputs.
465 lines
14 KiB
C++
465 lines
14 KiB
C++
// bench1.cpp - originally written and placed in the public domain by Wei Dai
|
|
// CryptoPP::Test namespace added by JW in February 2017
|
|
|
|
#include "cryptlib.h"
|
|
#include "bench.h"
|
|
#include "validate.h"
|
|
|
|
#include "cpu.h"
|
|
#include "drbg.h"
|
|
#include "factory.h"
|
|
#include "algparam.h"
|
|
#include "argnames.h"
|
|
#include "smartptr.h"
|
|
#include "stdcpp.h"
|
|
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
#if CRYPTOPP_MSC_VERSION
|
|
# pragma warning(disable: 4355)
|
|
#endif
|
|
|
|
#if CRYPTOPP_MSC_VERSION
|
|
# pragma warning(disable: 4505 4355)
|
|
#endif
|
|
|
|
NAMESPACE_BEGIN(CryptoPP)
|
|
NAMESPACE_BEGIN(Test)
|
|
|
|
#ifdef CLOCKS_PER_SEC
|
|
const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC;
|
|
#elif defined(CLK_TCK)
|
|
const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK;
|
|
#else
|
|
const double CLOCK_TICKS_PER_SECOND = 1000000.0;
|
|
#endif
|
|
|
|
extern const byte defaultKey[] = "0123456789" // 168 + NULL
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"00000000000000000000000000000000000000000000000000000"
|
|
"00000000000000000000000000000000000000000000000000000";
|
|
|
|
double g_allocatedTime = 0.0, g_hertz = 0.0, g_logTotal = 0.0;
|
|
unsigned int g_logCount = 0;
|
|
time_t g_testBegin, g_testEnd;
|
|
|
|
void OutputResultBytes(const char *name, const char *provider, double length, double timeTaken)
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
// Coverity finding
|
|
if (length < 0.000001f) length = 0.000001f;
|
|
if (timeTaken < 0.000001f) timeTaken = 0.000001f;
|
|
|
|
double mbs = length / timeTaken / (1024*1024);
|
|
oss << "\n<TR><TD>" << name << "<TD>" << provider;
|
|
oss << std::setiosflags(std::ios::fixed);
|
|
oss << "<TD>" << std::setprecision(0) << std::setiosflags(std::ios::fixed) << mbs;
|
|
if (g_hertz > 1.0f)
|
|
{
|
|
const double cpb = timeTaken * g_hertz / length;
|
|
if (cpb < 24.0f)
|
|
oss << "<TD>" << std::setprecision(2) << std::setiosflags(std::ios::fixed) << cpb;
|
|
else
|
|
oss << "<TD>" << std::setprecision(1) << std::setiosflags(std::ios::fixed) << cpb;
|
|
}
|
|
g_logTotal += log(mbs);
|
|
g_logCount++;
|
|
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
void OutputResultKeying(double iterations, double timeTaken)
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
// Coverity finding
|
|
if (iterations < 0.000001f) iterations = 0.000001f;
|
|
if (timeTaken < 0.000001f) timeTaken = 0.000001f;
|
|
|
|
oss << "<TD>" << std::setprecision(3) << std::setiosflags(std::ios::fixed) << (1000*1000*timeTaken/iterations);
|
|
|
|
// Coverity finding
|
|
if (g_hertz > 1.0f)
|
|
oss << "<TD>" << std::setprecision(0) << std::setiosflags(std::ios::fixed) << timeTaken * g_hertz / iterations;
|
|
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
void OutputResultOperations(const char *name, const char *provider, const char *operation, bool pc, unsigned long iterations, double timeTaken)
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
// Coverity finding
|
|
if (!iterations) iterations++;
|
|
if (timeTaken < 0.000001f) timeTaken = 0.000001f;
|
|
|
|
oss << "\n<TR><TD>" << name << " " << operation << (pc ? " with precomputation" : "");
|
|
oss << "<TD>" << provider;
|
|
oss << "<TD>" << std::setprecision(2) << std::setiosflags(std::ios::fixed) << (1000*timeTaken/iterations);
|
|
|
|
// Coverity finding
|
|
if (g_hertz > 1.0f)
|
|
{
|
|
const double t = timeTaken * g_hertz / iterations / 1000000;
|
|
oss << "<TD>" << std::setprecision(2) << std::setiosflags(std::ios::fixed) << t;
|
|
}
|
|
|
|
g_logTotal += log(iterations/timeTaken);
|
|
g_logCount++;
|
|
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
/*
|
|
void BenchMark(const char *name, BlockTransformation &cipher, double timeTotal)
|
|
{
|
|
const int BUF_SIZE = RoundUpToMultipleOf(2048U, cipher.OptimalNumberOfParallelBlocks() * cipher.BlockSize());
|
|
AlignedSecByteBlock buf(BUF_SIZE);
|
|
buf.SetMark(16);
|
|
|
|
const int nBlocks = BUF_SIZE / cipher.BlockSize();
|
|
unsigned long i=0, blocks=1;
|
|
double timeTaken;
|
|
|
|
clock_t start = ::clock();
|
|
do
|
|
{
|
|
blocks *= 2;
|
|
for (; i<blocks; i++)
|
|
cipher.ProcessAndXorMultipleBlocks(buf, NULLPTR, buf, nBlocks);
|
|
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
|
|
}
|
|
while (timeTaken < 2.0/3*timeTotal);
|
|
|
|
OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
|
|
}
|
|
*/
|
|
|
|
void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal)
|
|
{
|
|
const int BUF_SIZE=RoundUpToMultipleOf(2048U, cipher.OptimalBlockSize());
|
|
AlignedSecByteBlock buf(BUF_SIZE);
|
|
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
|
|
buf.SetMark(16);
|
|
|
|
unsigned long i=0, blocks=1;
|
|
double timeTaken;
|
|
|
|
clock_t start = ::clock();
|
|
do
|
|
{
|
|
blocks *= 2;
|
|
for (; i<blocks; i++)
|
|
cipher.ProcessString(buf, BUF_SIZE);
|
|
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
|
|
}
|
|
while (timeTaken < 2.0/3*timeTotal);
|
|
|
|
std::string provider = cipher.AlgorithmProvider();
|
|
OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken);
|
|
}
|
|
|
|
void BenchMark(const char *name, HashTransformation &ht, double timeTotal)
|
|
{
|
|
const int BUF_SIZE=2048U;
|
|
AlignedSecByteBlock buf(BUF_SIZE);
|
|
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
|
|
buf.SetMark(16);
|
|
|
|
unsigned long i=0, blocks=1;
|
|
double timeTaken;
|
|
|
|
clock_t start = ::clock();
|
|
do
|
|
{
|
|
blocks *= 2;
|
|
for (; i<blocks; i++)
|
|
ht.Update(buf, BUF_SIZE);
|
|
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
|
|
}
|
|
while (timeTaken < 2.0/3*timeTotal);
|
|
|
|
std::string provider = ht.AlgorithmProvider();
|
|
OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken);
|
|
}
|
|
|
|
void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal)
|
|
{
|
|
const int BUF_SIZE=2048U;
|
|
AlignedSecByteBlock buf(BUF_SIZE);
|
|
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
|
|
buf.SetMark(16);
|
|
|
|
unsigned long i=0, blocks=1;
|
|
double timeTaken;
|
|
|
|
clock_t start = ::clock();
|
|
do
|
|
{
|
|
blocks *= 2;
|
|
for (; i<blocks; i++)
|
|
bt.Put(buf, BUF_SIZE);
|
|
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
|
|
}
|
|
while (timeTaken < 2.0/3*timeTotal);
|
|
|
|
std::string provider = bt.AlgorithmProvider();
|
|
OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken);
|
|
}
|
|
|
|
void BenchMark(const char *name, RandomNumberGenerator &rng, double timeTotal)
|
|
{
|
|
const int BUF_SIZE = 2048U;
|
|
AlignedSecByteBlock buf(BUF_SIZE);
|
|
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
|
|
buf.SetMark(16);
|
|
|
|
SymmetricCipher * cipher = dynamic_cast<SymmetricCipher*>(&rng);
|
|
if (cipher != NULLPTR)
|
|
{
|
|
const size_t size = cipher->DefaultKeyLength();
|
|
if (cipher->IsResynchronizable())
|
|
cipher->SetKeyWithIV(buf, size, buf+size);
|
|
else
|
|
cipher->SetKey(buf, size);
|
|
}
|
|
|
|
unsigned long long blocks = 1;
|
|
double timeTaken;
|
|
|
|
clock_t start = ::clock();
|
|
do
|
|
{
|
|
rng.GenerateBlock(buf, buf.size());
|
|
blocks++;
|
|
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
|
|
} while (timeTaken < timeTotal);
|
|
|
|
std::string provider = rng.AlgorithmProvider();
|
|
OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken);
|
|
}
|
|
|
|
// Hack, but we probably need a KeyedRandomNumberGenerator interface
|
|
// and a few methods to generalize keying a RNG. X917RNG, Hash_DRBG,
|
|
// HMAC_DRBG, AES/CFB RNG and a few others could use it. "A few others"
|
|
// includes BLAKE2, ChaCha and Poly1305 when used as a RNG.
|
|
void BenchMark(const char *name, NIST_DRBG &rng, double timeTotal)
|
|
{
|
|
const int BUF_SIZE = 2048U;
|
|
AlignedSecByteBlock buf(BUF_SIZE);
|
|
Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);
|
|
buf.SetMark(16);
|
|
|
|
rng.IncorporateEntropy(buf, rng.MinEntropyLength());
|
|
unsigned long long blocks = 1;
|
|
double timeTaken;
|
|
|
|
clock_t start = ::clock();
|
|
do
|
|
{
|
|
rng.GenerateBlock(buf, buf.size());
|
|
blocks++;
|
|
timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
|
|
} while (timeTaken < timeTotal);
|
|
|
|
std::string provider = rng.AlgorithmProvider();
|
|
OutputResultBytes(name, provider.c_str(), double(blocks) * BUF_SIZE, timeTaken);
|
|
}
|
|
|
|
template <class T>
|
|
void BenchMarkByNameKeyLess(const char *factoryName, const char *displayName = NULLPTR, const NameValuePairs ¶ms = g_nullNameValuePairs)
|
|
{
|
|
CRYPTOPP_UNUSED(params);
|
|
std::string name = factoryName;
|
|
if (displayName)
|
|
name = displayName;
|
|
|
|
member_ptr<T> obj(ObjectFactoryRegistry<T>::Registry().CreateObject(factoryName));
|
|
BenchMark(name.c_str(), *obj, g_allocatedTime);
|
|
}
|
|
|
|
void AddHtmlHeader()
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
// HTML5
|
|
oss << "<!DOCTYPE HTML>";
|
|
oss << "\n<HTML lang=\"en\">";
|
|
|
|
oss << "\n<HEAD>";
|
|
oss << "\n<META charset=\"UTF-8\">";
|
|
oss << "\n<TITLE>Speed Comparison of Popular Crypto Algorithms</TITLE>";
|
|
oss << "\n<STYLE>\n table {border-collapse: collapse;}";
|
|
oss << "\n table, th, td, tr {border: 1px solid black;}\n</STYLE>";
|
|
oss << "\n</HEAD>";
|
|
|
|
oss << "\n<BODY>";
|
|
|
|
oss << "\n<H1><A href=\"http://www.cryptopp.com\">Crypto++</A> " << CRYPTOPP_VERSION / 100;
|
|
oss << '.' << (CRYPTOPP_VERSION % 100) / 10 << '.' << CRYPTOPP_VERSION % 10 << " Benchmarks</H1>";
|
|
|
|
oss << "\n<P>Here are speed benchmarks for some commonly used cryptographic algorithms.</P>";
|
|
|
|
if (g_hertz > 1.0f)
|
|
oss << "\n<P>CPU frequency of the test platform is " << g_hertz << " Hz.</P>";
|
|
else
|
|
oss << "\n<P>CPU frequency of the test platform was not provided.</P>" << std::endl;
|
|
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
void AddHtmlFooter()
|
|
{
|
|
std::ostringstream oss;
|
|
std::cout << "\n</BODY>";
|
|
std::cout << "\n</HTML>" << std::endl;
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
void BenchmarkWithCommand(int argc, const char* const argv[])
|
|
{
|
|
std::string command(argv[1]);
|
|
float runningTime(argc >= 3 ? Test::StringToValue<float, true>(argv[2]) : 1.0f);
|
|
float cpuFreq(argc >= 4 ? Test::StringToValue<float, true>(argv[3])*float(1e9) : 0.0f);
|
|
std::string algoName(argc >= 5 ? argv[4] : "");
|
|
|
|
if (command == "b") // All benchmarks
|
|
Benchmark(Test::All, runningTime, cpuFreq);
|
|
else if (command == "b3") // Public key algorithms
|
|
Test::Benchmark(Test::PublicKey, runningTime, cpuFreq);
|
|
else if (command == "b2") // Shared key algorithms
|
|
Test::Benchmark(Test::SharedKey, runningTime, cpuFreq);
|
|
else if (command == "b1") // Unkeyed algorithms
|
|
Test::Benchmark(Test::Unkeyed, runningTime, cpuFreq);
|
|
}
|
|
|
|
void Benchmark(Test::TestClass suites, double t, double hertz)
|
|
{
|
|
g_allocatedTime = t;
|
|
g_hertz = hertz;
|
|
std::ostringstream oss;
|
|
|
|
AddHtmlHeader();
|
|
|
|
g_testBegin = ::time(NULLPTR);
|
|
|
|
if (static_cast<int>(suites) == 0 || static_cast<int>(suites) > TestLast)
|
|
suites = Test::All;
|
|
|
|
// Unkeyed algorithms
|
|
if (suites & Test::Unkeyed)
|
|
{
|
|
oss << "\n<BR>";
|
|
Benchmark1(t, hertz);
|
|
}
|
|
|
|
// Shared key algorithms
|
|
if (suites & Test::SharedKey)
|
|
{
|
|
oss << "\n<BR>";
|
|
Benchmark2(t, hertz);
|
|
}
|
|
|
|
// Public key algorithms
|
|
if (suites & Test::PublicKey)
|
|
{
|
|
oss << "\n<BR>";
|
|
Benchmark3(t, hertz);
|
|
}
|
|
|
|
g_testEnd = ::time(NULLPTR);
|
|
|
|
oss << "\n<P>Throughput Geometric Average: " << std::setiosflags(std::ios::fixed);
|
|
oss << std::exp(g_logTotal/(g_logCount > 0.0f ? g_logCount : 1.0f)) << std::endl;
|
|
|
|
oss << "\n<P>Test started at " << TimeToString(g_testBegin);
|
|
oss << "\n<BR>Test ended at " << TimeToString(g_testEnd);
|
|
oss << std::endl;
|
|
|
|
AddHtmlFooter();
|
|
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
void Benchmark1(double t, double hertz)
|
|
{
|
|
g_allocatedTime = t;
|
|
g_hertz = hertz;
|
|
|
|
const char *cpb;
|
|
if (g_hertz > 1.0f)
|
|
cpb = "<TH>Cycles Per Byte";
|
|
else
|
|
cpb = "";
|
|
|
|
std::cout << "\n<TABLE>";
|
|
|
|
std::cout << "\n<COLGROUP><COL style=\"text-align: left;\"><COL style=\"text-align: right;\">";
|
|
std::cout << "<COL style=\"text-align: right;\">";
|
|
std::cout << "\n<THEAD style=\"background: #F0F0F0\">";
|
|
std::cout << "\n<TR><TH>Algorithm<TH>Provider<TH>MiB/Second" << cpb;
|
|
|
|
std::cout << "\n<TBODY style=\"background: white;\">";
|
|
{
|
|
#ifdef NONBLOCKING_RNG_AVAILABLE
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("NonblockingRng");
|
|
#endif
|
|
#ifdef OS_RNG_AVAILABLE
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("AutoSeededRandomPool");
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("AutoSeededX917RNG(AES)");
|
|
#endif
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("MT19937");
|
|
#if (CRYPTOPP_BOOL_X86)
|
|
if (HasPadlockRNG())
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("PadlockRNG");
|
|
#endif
|
|
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
|
|
if (HasRDRAND())
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("RDRAND");
|
|
if (HasRDSEED())
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("RDSEED");
|
|
#endif
|
|
BenchMarkByNameKeyLess<RandomNumberGenerator>("AES/OFB RNG");
|
|
BenchMarkByNameKeyLess<NIST_DRBG>("Hash_DRBG(SHA1)");
|
|
BenchMarkByNameKeyLess<NIST_DRBG>("Hash_DRBG(SHA256)");
|
|
BenchMarkByNameKeyLess<NIST_DRBG>("HMAC_DRBG(SHA1)");
|
|
BenchMarkByNameKeyLess<NIST_DRBG>("HMAC_DRBG(SHA256)");
|
|
}
|
|
|
|
std::cout << "\n<TBODY style=\"background: yellow;\">";
|
|
{
|
|
BenchMarkByNameKeyLess<HashTransformation>("CRC32");
|
|
BenchMarkByNameKeyLess<HashTransformation>("CRC32C");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Adler32");
|
|
BenchMarkByNameKeyLess<HashTransformation>("MD5");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA-1");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA-256");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA-512");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA3-224");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA3-256");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA3-384");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SHA3-512");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Keccak-224");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Keccak-256");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Keccak-384");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Keccak-512");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Tiger");
|
|
BenchMarkByNameKeyLess<HashTransformation>("Whirlpool");
|
|
BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-160");
|
|
BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-320");
|
|
BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-128");
|
|
BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-256");
|
|
BenchMarkByNameKeyLess<HashTransformation>("SM3");
|
|
BenchMarkByNameKeyLess<HashTransformation>("BLAKE2s");
|
|
BenchMarkByNameKeyLess<HashTransformation>("BLAKE2b");
|
|
}
|
|
|
|
std::cout << "\n</TABLE>" << std::endl;
|
|
}
|
|
|
|
NAMESPACE_END // Test
|
|
NAMESPACE_END // CryptoPP
|