00001
00002
00003 #include "cryptlib.h"
00004 #include "bench.h"
00005 #include "validate.h"
00006
00007 #include "aes.h"
00008 #include "blumshub.h"
00009 #include "files.h"
00010 #include "filters.h"
00011 #include "hex.h"
00012 #include "modes.h"
00013 #include "factory.h"
00014 #include "smartptr.h"
00015 #include "cpu.h"
00016
00017 #include <time.h>
00018 #include <math.h>
00019 #include <iostream>
00020 #include <sstream>
00021 #include <iomanip>
00022
00023
00024 #if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
00025 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00026 #endif
00027
00028 USING_NAMESPACE(CryptoPP)
00029 USING_NAMESPACE(std)
00030
00031 #ifdef CLOCKS_PER_SEC
00032 const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC;
00033 #elif defined(CLK_TCK)
00034 const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK;
00035 #else
00036 const double CLOCK_TICKS_PER_SECOND = 1000000.0;
00037 #endif
00038
00039 double logtotal = 0.0, g_allocatedTime = 0, g_hertz = 0;
00040 unsigned int logcount = 0;
00041
00042 static const byte defaultKey[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
00043 "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
00044
00045 void OutputResultBytes(const char *name, double length, double timeTaken)
00046 {
00047
00048 std::ostringstream out;
00049 out.copyfmt(cout);
00050
00051
00052 if (length < 0.0000000001f) length = 0.000001f;
00053 if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
00054
00055 double mbs = length / timeTaken / (1024*1024);
00056 out << "\n<TR><TH>" << name;
00057
00058 out << setiosflags(ios::fixed);
00059
00060 out << "<TD>" << setprecision(0) << setiosflags(ios::fixed) << mbs;
00061 if (g_hertz)
00062 out << "<TD>" << setprecision(1) << setiosflags(ios::fixed) << timeTaken * g_hertz / length;
00063 logtotal += log(mbs);
00064 logcount++;
00065
00066 cout << out.str();
00067 }
00068
00069 void OutputResultKeying(double iterations, double timeTaken)
00070 {
00071
00072 std::ostringstream out;
00073 out.copyfmt(cout);
00074
00075
00076 if (iterations < 0.0000000001f) iterations = 0.000001f;
00077 if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
00078
00079 out << "<TD>" << setprecision(3) << setiosflags(ios::fixed) << (1000*1000*timeTaken/iterations);
00080 if (g_hertz)
00081 out << "<TD>" << setprecision(0) << setiosflags(ios::fixed) << timeTaken * g_hertz / iterations;
00082
00083 cout << out.str();
00084 }
00085
00086 void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken)
00087 {
00088
00089 std::ostringstream out;
00090 out.copyfmt(cout);
00091
00092
00093 if (!iterations) iterations++;
00094 if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
00095
00096 out << "\n<TR><TH>" << name << " " << operation << (pc ? " with precomputation" : "");
00097 out << "<TD>" << setprecision(2) << setiosflags(ios::fixed) << (1000*timeTaken/iterations);
00098 if (g_hertz)
00099 out << "<TD>" << setprecision(2) << setiosflags(ios::fixed) << timeTaken * g_hertz / iterations / 1000000;
00100
00101 logtotal += log(iterations/timeTaken);
00102 logcount++;
00103
00104 cout << out.str();
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal)
00131 {
00132 const int BUF_SIZE=RoundUpToMultipleOf(2048U, cipher.OptimalBlockSize());
00133 AlignedSecByteBlock buf(BUF_SIZE);
00134 GlobalRNG().GenerateBlock(buf, BUF_SIZE);
00135 clock_t start = clock();
00136
00137 unsigned long i=0, blocks=1;
00138 double timeTaken;
00139 do
00140 {
00141 blocks *= 2;
00142 for (; i<blocks; i++)
00143 cipher.ProcessString(buf, BUF_SIZE);
00144 timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
00145 }
00146 while (timeTaken < 2.0/3*timeTotal);
00147
00148 OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
00149 }
00150
00151 void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal)
00152 {
00153 if (cipher.NeedsPrespecifiedDataLengths())
00154 cipher.SpecifyDataLengths(0, cipher.MaxMessageLength(), 0);
00155
00156 BenchMark(name, static_cast<StreamTransformation &>(cipher), timeTotal);
00157 }
00158
00159 void BenchMark(const char *name, HashTransformation &ht, double timeTotal)
00160 {
00161 const int BUF_SIZE=2048U;
00162 AlignedSecByteBlock buf(BUF_SIZE);
00163 GlobalRNG().GenerateBlock(buf, BUF_SIZE);
00164 clock_t start = clock();
00165
00166 unsigned long i=0, blocks=1;
00167 double timeTaken;
00168 do
00169 {
00170 blocks *= 2;
00171 for (; i<blocks; i++)
00172 ht.Update(buf, BUF_SIZE);
00173 timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
00174 }
00175 while (timeTaken < 2.0/3*timeTotal);
00176
00177 OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
00178 }
00179
00180 void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal)
00181 {
00182 const int BUF_SIZE=2048U;
00183 AlignedSecByteBlock buf(BUF_SIZE);
00184 GlobalRNG().GenerateBlock(buf, BUF_SIZE);
00185 clock_t start = clock();
00186
00187 unsigned long i=0, blocks=1;
00188 double timeTaken;
00189 do
00190 {
00191 blocks *= 2;
00192 for (; i<blocks; i++)
00193 bt.Put(buf, BUF_SIZE);
00194 timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
00195 }
00196 while (timeTaken < 2.0/3*timeTotal);
00197
00198 OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
00199 }
00200
00201 void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs ¶ms)
00202 {
00203 unsigned long iterations = 0;
00204 clock_t start = clock();
00205 double timeTaken;
00206 do
00207 {
00208 for (unsigned int i=0; i<1024; i++)
00209 c.SetKey(defaultKey, keyLength, params);
00210 timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
00211 iterations += 1024;
00212 }
00213 while (timeTaken < g_allocatedTime);
00214
00215 OutputResultKeying(iterations, timeTaken);
00216 }
00217
00218
00219
00220 template <class T_FactoryOutput, class T_Interface>
00221 void BenchMarkByName2(const char *factoryName, size_t keyLength = 0, const char *displayName=NULL, const NameValuePairs ¶ms = g_nullNameValuePairs, T_FactoryOutput *x=NULL, T_Interface *y=NULL)
00222 {
00223 CRYPTOPP_UNUSED(x), CRYPTOPP_UNUSED(y), CRYPTOPP_UNUSED(params);
00224
00225 std::string name(factoryName ? factoryName : "");
00226 member_ptr<T_FactoryOutput> obj(ObjectFactoryRegistry<T_FactoryOutput>::Registry().CreateObject(name.c_str()));
00227
00228 if (!keyLength)
00229 keyLength = obj->DefaultKeyLength();
00230
00231 if (displayName)
00232 name = displayName;
00233 else if (keyLength)
00234 name += " (" + IntToString(keyLength * 8) + "-bit key)";
00235
00236 obj->SetKey(defaultKey, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(defaultKey, obj->IVSize()), false)));
00237 BenchMark(name.c_str(), *static_cast<T_Interface *>(obj.get()), g_allocatedTime);
00238 BenchMarkKeying(*obj, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(defaultKey, obj->IVSize()), false)));
00239 }
00240
00241
00242 template <class T_FactoryOutput>
00243 void BenchMarkByName(const char *factoryName, size_t keyLength = 0, const char *displayName=NULL, const NameValuePairs ¶ms = g_nullNameValuePairs, T_FactoryOutput *x=NULL)
00244 {
00245 CRYPTOPP_UNUSED(x), CRYPTOPP_UNUSED(params);
00246
00247 BenchMarkByName2<T_FactoryOutput, T_FactoryOutput>(factoryName, keyLength, displayName, params, x, x);
00248 }
00249
00250 template <class T>
00251 void BenchMarkByNameKeyLess(const char *factoryName, const char *displayName=NULL, const NameValuePairs ¶ms = g_nullNameValuePairs, T *x=NULL)
00252 {
00253 CRYPTOPP_UNUSED(x), CRYPTOPP_UNUSED(params);
00254
00255 std::string name = factoryName;
00256 if (displayName)
00257 name = displayName;
00258
00259 member_ptr<T> obj(ObjectFactoryRegistry<T>::Registry().CreateObject(factoryName));
00260 BenchMark(name.c_str(), *obj, g_allocatedTime);
00261 }
00262
00263 void BenchmarkAll(double t, double hertz)
00264 {
00265 #if 1
00266 logtotal = 0;
00267 logcount = 0;
00268 g_allocatedTime = t;
00269 g_hertz = hertz;
00270
00271 const char *cpb, *cpk;
00272 if (g_hertz)
00273 {
00274 cpb = "<TH>Cycles Per Byte";
00275 cpk = "<TH>Cycles to<br>Setup Key and IV";
00276 cout << "CPU frequency of the test platform is " << g_hertz << " Hz.\n";
00277 }
00278 else
00279 {
00280 cpb = cpk = "";
00281 cout << "CPU frequency of the test platform was not provided.\n";
00282 }
00283
00284 cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right><COL align=right><COL align=right>" << endl;
00285 cout << "<THEAD><TR><TH>Algorithm<TH>MiB/Second" << cpb << "<TH>Microseconds to<br>Setup Key and IV" << cpk << endl;
00286
00287 cout << "\n<TBODY style=\"background: yellow\">";
00288 #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
00289 if (HasCLMUL())
00290 BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
00291 else
00292 #endif
00293 {
00294 BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (2K tables)", MakeParameters(Name::TableSize(), 2048));
00295 BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
00296 }
00297 BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/CCM");
00298 BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/EAX");
00299
00300 cout << "\n<TBODY style=\"background: white\">";
00301 #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
00302 if (HasCLMUL())
00303 BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES)");
00304 else
00305 #endif
00306 {
00307 BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (2K tables)", MakeParameters(Name::TableSize(), 2048));
00308 BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
00309 }
00310 BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-64");
00311 BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-128");
00312 BenchMarkByName<MessageAuthenticationCode>("HMAC(SHA-1)");
00313 BenchMarkByName<MessageAuthenticationCode>("Two-Track-MAC");
00314 BenchMarkByName<MessageAuthenticationCode>("CMAC(AES)");
00315 BenchMarkByName<MessageAuthenticationCode>("DMAC(AES)");
00316
00317 cout << "\n<TBODY style=\"background: yellow\">";
00318 BenchMarkByNameKeyLess<HashTransformation>("CRC32");
00319 BenchMarkByNameKeyLess<HashTransformation>("Adler32");
00320 BenchMarkByNameKeyLess<HashTransformation>("MD5");
00321 BenchMarkByNameKeyLess<HashTransformation>("SHA-1");
00322 BenchMarkByNameKeyLess<HashTransformation>("SHA-256");
00323 BenchMarkByNameKeyLess<HashTransformation>("SHA-512");
00324 BenchMarkByNameKeyLess<HashTransformation>("SHA-3-224");
00325 BenchMarkByNameKeyLess<HashTransformation>("SHA-3-256");
00326 BenchMarkByNameKeyLess<HashTransformation>("SHA-3-384");
00327 BenchMarkByNameKeyLess<HashTransformation>("SHA-3-512");
00328 BenchMarkByNameKeyLess<HashTransformation>("Tiger");
00329 BenchMarkByNameKeyLess<HashTransformation>("Whirlpool");
00330 BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-160");
00331 BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-320");
00332 BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-128");
00333 BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-256");
00334
00335 cout << "\n<TBODY style=\"background: white\">";
00336 BenchMarkByName<SymmetricCipher>("Panama-LE");
00337 BenchMarkByName<SymmetricCipher>("Panama-BE");
00338 BenchMarkByName<SymmetricCipher>("Salsa20");
00339 BenchMarkByName<SymmetricCipher>("Salsa20", 0, "Salsa20/12", MakeParameters(Name::Rounds(), 12));
00340 BenchMarkByName<SymmetricCipher>("Salsa20", 0, "Salsa20/8", MakeParameters(Name::Rounds(), 8));
00341 BenchMarkByName<SymmetricCipher>("Sosemanuk");
00342 BenchMarkByName<SymmetricCipher>("MARC4");
00343 BenchMarkByName<SymmetricCipher>("SEAL-3.0-LE");
00344 BenchMarkByName<SymmetricCipher>("WAKE-OFB-LE");
00345
00346 cout << "\n<TBODY style=\"background: yellow\">";
00347 BenchMarkByName<SymmetricCipher>("AES/CTR", 16);
00348 BenchMarkByName<SymmetricCipher>("AES/CTR", 24);
00349 BenchMarkByName<SymmetricCipher>("AES/CTR", 32);
00350 BenchMarkByName<SymmetricCipher>("AES/CBC", 16);
00351 BenchMarkByName<SymmetricCipher>("AES/CBC", 24);
00352 BenchMarkByName<SymmetricCipher>("AES/CBC", 32);
00353 BenchMarkByName<SymmetricCipher>("AES/OFB", 16);
00354 BenchMarkByName<SymmetricCipher>("AES/CFB", 16);
00355 BenchMarkByName<SymmetricCipher>("AES/ECB", 16);
00356 BenchMarkByName<SymmetricCipher>("Camellia/CTR", 16);
00357 BenchMarkByName<SymmetricCipher>("Camellia/CTR", 32);
00358 BenchMarkByName<SymmetricCipher>("Twofish/CTR");
00359 BenchMarkByName<SymmetricCipher>("Serpent/CTR");
00360 BenchMarkByName<SymmetricCipher>("CAST-256/CTR");
00361 BenchMarkByName<SymmetricCipher>("RC6/CTR");
00362 BenchMarkByName<SymmetricCipher>("MARS/CTR");
00363 BenchMarkByName<SymmetricCipher>("SHACAL-2/CTR", 16);
00364 BenchMarkByName<SymmetricCipher>("SHACAL-2/CTR", 64);
00365 BenchMarkByName<SymmetricCipher>("DES/CTR");
00366 BenchMarkByName<SymmetricCipher>("DES-XEX3/CTR");
00367 BenchMarkByName<SymmetricCipher>("DES-EDE3/CTR");
00368 BenchMarkByName<SymmetricCipher>("IDEA/CTR");
00369 BenchMarkByName<SymmetricCipher>("RC5/CTR", 0, "RC5 (r=16)");
00370 BenchMarkByName<SymmetricCipher>("Blowfish/CTR");
00371 BenchMarkByName<SymmetricCipher>("TEA/CTR");
00372 BenchMarkByName<SymmetricCipher>("XTEA/CTR");
00373 BenchMarkByName<SymmetricCipher>("CAST-128/CTR");
00374 BenchMarkByName<SymmetricCipher>("SKIPJACK/CTR");
00375 BenchMarkByName<SymmetricCipher>("SEED/CTR", 0, "SEED/CTR (1/2 K table)");
00376 cout << "</TABLE>" << endl;
00377
00378 BenchmarkAll2(t, hertz);
00379 cout << "Throughput Geometric Average: " << setiosflags(ios::fixed) << exp(logtotal/(logcount ? logcount : 1)) << endl;
00380
00381
00382 #if (CRYPTOPP_MSC_VERSION >= 1400)
00383 tm localTime = {};
00384 char timeBuf[64];
00385 errno_t err;
00386
00387 const time_t endTime = time(NULL);
00388 err = localtime_s(&localTime, &endTime);
00389 assert(err == 0);
00390 err = asctime_s(timeBuf, sizeof(timeBuf), &localTime);
00391 assert(err == 0);
00392
00393 cout << "\nTest ended at " << timeBuf;
00394 #else
00395 const time_t endTime = time(NULL);
00396 cout << "\nTest ended at " << asctime(localtime(&endTime));
00397 #endif
00398 #endif
00399 }