Crypto++
bench.cpp
1 // bench.cpp - written and placed in the public domain by Wei Dai
2 
3 #define _CRT_SECURE_NO_DEPRECATE
4 
5 #include "bench.h"
6 #include "validate.h"
7 #include "aes.h"
8 #include "blumshub.h"
9 #include "files.h"
10 #include "hex.h"
11 #include "modes.h"
12 #include "factory.h"
13 #include "cpu.h"
14 
15 #include <time.h>
16 #include <math.h>
17 #include <iostream>
18 #include <iomanip>
19 
20 USING_NAMESPACE(CryptoPP)
21 USING_NAMESPACE(std)
22 
23 #ifdef CLOCKS_PER_SEC
24 const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC;
25 #elif defined(CLK_TCK)
26 const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK;
27 #else
28 const double CLOCK_TICKS_PER_SECOND = 1000000.0;
29 #endif
30 
31 double logtotal = 0, g_allocatedTime, g_hertz;
32 unsigned int logcount = 0;
33 
34 static const byte *const key=(byte *)"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
35 
36 void OutputResultBytes(const char *name, double length, double timeTaken)
37 {
38  double mbs = length / timeTaken / (1024*1024);
39  cout << "\n<TR><TH>" << name;
40 // cout << "<TD>" << setprecision(3) << length / (1024*1024);
41  cout << setiosflags(ios::fixed);
42 // cout << "<TD>" << setprecision(3) << timeTaken;
43  cout << "<TD>" << setprecision(0) << setiosflags(ios::fixed) << mbs;
44  if (g_hertz)
45  cout << "<TD>" << setprecision(1) << setiosflags(ios::fixed) << timeTaken * g_hertz / length;
46  cout << resetiosflags(ios::fixed);
47  logtotal += log(mbs);
48  logcount++;
49 }
50 
51 void OutputResultKeying(double iterations, double timeTaken)
52 {
53  cout << "<TD>" << setprecision(3) << setiosflags(ios::fixed) << (1000*1000*timeTaken/iterations);
54  if (g_hertz)
55  cout << "<TD>" << setprecision(0) << setiosflags(ios::fixed) << timeTaken * g_hertz / iterations;
56 }
57 
58 void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken)
59 {
60  cout << "\n<TR><TH>" << name << " " << operation << (pc ? " with precomputation" : "");
61 // cout << "<TD>" << iterations;
62 // cout << setiosflags(ios::fixed);
63 // cout << "<TD>" << setprecision(3) << timeTaken;
64  cout << "<TD>" << setprecision(2) << setiosflags(ios::fixed) << (1000*timeTaken/iterations);
65  if (g_hertz)
66  cout << "<TD>" << setprecision(2) << setiosflags(ios::fixed) << timeTaken * g_hertz / iterations / 1000000;
67  cout << resetiosflags(ios::fixed);
68 
69  logtotal += log(iterations/timeTaken);
70  logcount++;
71 }
72 
73 /*
74 void BenchMark(const char *name, BlockTransformation &cipher, double timeTotal)
75 {
76  const int BUF_SIZE = RoundUpToMultipleOf(2048U, cipher.OptimalNumberOfParallelBlocks() * cipher.BlockSize());
77  AlignedSecByteBlock buf(BUF_SIZE);
78  const int nBlocks = BUF_SIZE / cipher.BlockSize();
79  clock_t start = clock();
80 
81  unsigned long i=0, blocks=1;
82  double timeTaken;
83  do
84  {
85  blocks *= 2;
86  for (; i<blocks; i++)
87  cipher.ProcessAndXorMultipleBlocks(buf, NULL, buf, nBlocks);
88  timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
89  }
90  while (timeTaken < 2.0/3*timeTotal);
91 
92  OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
93 }
94 */
95 
96 void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal)
97 {
98  const int BUF_SIZE=RoundUpToMultipleOf(2048U, cipher.OptimalBlockSize());
99  AlignedSecByteBlock buf(BUF_SIZE);
100  GlobalRNG().GenerateBlock(buf, BUF_SIZE);
101  clock_t start = clock();
102 
103  unsigned long i=0, blocks=1;
104  double timeTaken;
105  do
106  {
107  blocks *= 2;
108  for (; i<blocks; i++)
109  cipher.ProcessString(buf, BUF_SIZE);
110  timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
111  }
112  while (timeTaken < 2.0/3*timeTotal);
113 
114  OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
115 }
116 
117 void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal)
118 {
119  if (cipher.NeedsPrespecifiedDataLengths())
120  cipher.SpecifyDataLengths(0, cipher.MaxMessageLength(), 0);
121 
122  BenchMark(name, static_cast<StreamTransformation &>(cipher), timeTotal);
123 }
124 
125 void BenchMark(const char *name, HashTransformation &ht, double timeTotal)
126 {
127  const int BUF_SIZE=2048U;
128  AlignedSecByteBlock buf(BUF_SIZE);
129  GlobalRNG().GenerateBlock(buf, BUF_SIZE);
130  clock_t start = clock();
131 
132  unsigned long i=0, blocks=1;
133  double timeTaken;
134  do
135  {
136  blocks *= 2;
137  for (; i<blocks; i++)
138  ht.Update(buf, BUF_SIZE);
139  timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
140  }
141  while (timeTaken < 2.0/3*timeTotal);
142 
143  OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
144 }
145 
146 void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal)
147 {
148  const int BUF_SIZE=2048U;
149  AlignedSecByteBlock buf(BUF_SIZE);
150  GlobalRNG().GenerateBlock(buf, BUF_SIZE);
151  clock_t start = clock();
152 
153  unsigned long i=0, blocks=1;
154  double timeTaken;
155  do
156  {
157  blocks *= 2;
158  for (; i<blocks; i++)
159  bt.Put(buf, BUF_SIZE);
160  timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
161  }
162  while (timeTaken < 2.0/3*timeTotal);
163 
164  OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
165 }
166 
167 void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs &params)
168 {
169  unsigned long iterations = 0;
170  clock_t start = clock();
171  double timeTaken;
172  do
173  {
174  for (unsigned int i=0; i<1024; i++)
175  c.SetKey(key, keyLength, params);
176  timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
177  iterations += 1024;
178  }
179  while (timeTaken < g_allocatedTime);
180 
181  OutputResultKeying(iterations, timeTaken);
182 }
183 
184 //VC60 workaround: compiler bug triggered without the extra dummy parameters
185 // on VC60 also needs to be named differently from BenchMarkByName
186 template <class T_FactoryOutput, class T_Interface>
187 void BenchMarkByName2(const char *factoryName, size_t keyLength = 0, const char *displayName=NULL, const NameValuePairs &params = g_nullNameValuePairs, T_FactoryOutput *x=NULL, T_Interface *y=NULL)
188 {
189  std::string name = factoryName;
190  if (displayName)
191  name = displayName;
192  else if (keyLength)
193  name += " (" + IntToString(keyLength * 8) + "-bit key)";
194 
195  std::auto_ptr<T_FactoryOutput> obj(ObjectFactoryRegistry<T_FactoryOutput>::Registry().CreateObject(factoryName));
196  if (!keyLength)
197  keyLength = obj->DefaultKeyLength();
198  obj->SetKey(key, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(key, obj->IVSize()), false)));
199  BenchMark(name.c_str(), *static_cast<T_Interface *>(obj.get()), g_allocatedTime);
200  BenchMarkKeying(*obj, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(key, obj->IVSize()), false)));
201 }
202 
203 //VC60 workaround: compiler bug triggered without the extra dummy parameters
204 template <class T_FactoryOutput>
205 void BenchMarkByName(const char *factoryName, size_t keyLength = 0, const char *displayName=NULL, const NameValuePairs &params = g_nullNameValuePairs, T_FactoryOutput *x=NULL)
206 {
207  BenchMarkByName2<T_FactoryOutput, T_FactoryOutput>(factoryName, keyLength, displayName, params, x, x);
208 }
209 
210 template <class T>
211 void BenchMarkByNameKeyLess(const char *factoryName, const char *displayName=NULL, const NameValuePairs &params = g_nullNameValuePairs, T *x=NULL)
212 {
213  std::string name = factoryName;
214  if (displayName)
215  name = displayName;
216 
217  std::auto_ptr<T> obj(ObjectFactoryRegistry<T>::Registry().CreateObject(factoryName));
218  BenchMark(name.c_str(), *obj, g_allocatedTime);
219 }
220 
221 void BenchmarkAll(double t, double hertz)
222 {
223 #if 1
224  logtotal = 0;
225  logcount = 0;
226  g_allocatedTime = t;
227  g_hertz = hertz;
228 
229  const char *cpb, *cpk;
230  if (g_hertz)
231  {
232  cpb = "<TH>Cycles Per Byte";
233  cpk = "<TH>Cycles to<br>Setup Key and IV";
234  cout << "CPU frequency of the test platform is " << g_hertz << " Hz.\n";
235  }
236  else
237  {
238  cpb = cpk = "";
239  cout << "CPU frequency of the test platform was not provided.\n";
240  }
241 
242  cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right><COL align=right><COL align=right>" << endl;
243  cout << "<THEAD><TR><TH>Algorithm<TH>MiB/Second" << cpb << "<TH>Microseconds to<br>Setup Key and IV" << cpk << endl;
244 
245  cout << "\n<TBODY style=\"background: yellow\">";
246 #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
247  if (HasCLMUL())
248  BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
249  else
250 #endif
251  {
252  BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (2K tables)", MakeParameters(Name::TableSize(), 2048));
253  BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
254  }
255  BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/CCM");
256  BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/EAX");
257 
258  cout << "\n<TBODY style=\"background: white\">";
259 #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
260  if (HasCLMUL())
261  BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES)");
262  else
263 #endif
264  {
265  BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (2K tables)", MakeParameters(Name::TableSize(), 2048));
266  BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
267  }
268  BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-64");
269  BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-128");
270  BenchMarkByName<MessageAuthenticationCode>("HMAC(SHA-1)");
271  BenchMarkByName<MessageAuthenticationCode>("Two-Track-MAC");
272  BenchMarkByName<MessageAuthenticationCode>("CMAC(AES)");
273  BenchMarkByName<MessageAuthenticationCode>("DMAC(AES)");
274 
275  cout << "\n<TBODY style=\"background: yellow\">";
276  BenchMarkByNameKeyLess<HashTransformation>("CRC32");
277  BenchMarkByNameKeyLess<HashTransformation>("Adler32");
278  BenchMarkByNameKeyLess<HashTransformation>("MD5");
279  BenchMarkByNameKeyLess<HashTransformation>("SHA-1");
280  BenchMarkByNameKeyLess<HashTransformation>("SHA-256");
281  BenchMarkByNameKeyLess<HashTransformation>("SHA-512");
282  BenchMarkByNameKeyLess<HashTransformation>("SHA-3-224");
283  BenchMarkByNameKeyLess<HashTransformation>("SHA-3-256");
284  BenchMarkByNameKeyLess<HashTransformation>("SHA-3-384");
285  BenchMarkByNameKeyLess<HashTransformation>("SHA-3-512");
286  BenchMarkByNameKeyLess<HashTransformation>("Tiger");
287  BenchMarkByNameKeyLess<HashTransformation>("Whirlpool");
288  BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-160");
289  BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-320");
290  BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-128");
291  BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-256");
292 
293  cout << "\n<TBODY style=\"background: white\">";
294  BenchMarkByName<SymmetricCipher>("Panama-LE");
295  BenchMarkByName<SymmetricCipher>("Panama-BE");
296  BenchMarkByName<SymmetricCipher>("Salsa20");
297  BenchMarkByName<SymmetricCipher>("Salsa20", 0, "Salsa20/12", MakeParameters(Name::Rounds(), 12));
298  BenchMarkByName<SymmetricCipher>("Salsa20", 0, "Salsa20/8", MakeParameters(Name::Rounds(), 8));
299  BenchMarkByName<SymmetricCipher>("Sosemanuk");
300  BenchMarkByName<SymmetricCipher>("MARC4");
301  BenchMarkByName<SymmetricCipher>("SEAL-3.0-LE");
302  BenchMarkByName<SymmetricCipher>("WAKE-OFB-LE");
303 
304  cout << "\n<TBODY style=\"background: yellow\">";
305  BenchMarkByName<SymmetricCipher>("AES/CTR", 16);
306  BenchMarkByName<SymmetricCipher>("AES/CTR", 24);
307  BenchMarkByName<SymmetricCipher>("AES/CTR", 32);
308  BenchMarkByName<SymmetricCipher>("AES/CBC", 16);
309  BenchMarkByName<SymmetricCipher>("AES/CBC", 24);
310  BenchMarkByName<SymmetricCipher>("AES/CBC", 32);
311  BenchMarkByName<SymmetricCipher>("AES/OFB", 16);
312  BenchMarkByName<SymmetricCipher>("AES/CFB", 16);
313  BenchMarkByName<SymmetricCipher>("AES/ECB", 16);
314  BenchMarkByName<SymmetricCipher>("Camellia/CTR", 16);
315  BenchMarkByName<SymmetricCipher>("Camellia/CTR", 32);
316  BenchMarkByName<SymmetricCipher>("Twofish/CTR");
317  BenchMarkByName<SymmetricCipher>("Serpent/CTR");
318  BenchMarkByName<SymmetricCipher>("CAST-256/CTR");
319  BenchMarkByName<SymmetricCipher>("RC6/CTR");
320  BenchMarkByName<SymmetricCipher>("MARS/CTR");
321  BenchMarkByName<SymmetricCipher>("SHACAL-2/CTR", 16);
322  BenchMarkByName<SymmetricCipher>("SHACAL-2/CTR", 64);
323  BenchMarkByName<SymmetricCipher>("DES/CTR");
324  BenchMarkByName<SymmetricCipher>("DES-XEX3/CTR");
325  BenchMarkByName<SymmetricCipher>("DES-EDE3/CTR");
326  BenchMarkByName<SymmetricCipher>("IDEA/CTR");
327  BenchMarkByName<SymmetricCipher>("RC5/CTR", 0, "RC5 (r=16)");
328  BenchMarkByName<SymmetricCipher>("Blowfish/CTR");
329  BenchMarkByName<SymmetricCipher>("TEA/CTR");
330  BenchMarkByName<SymmetricCipher>("XTEA/CTR");
331  BenchMarkByName<SymmetricCipher>("CAST-128/CTR");
332  BenchMarkByName<SymmetricCipher>("SKIPJACK/CTR");
333  BenchMarkByName<SymmetricCipher>("SEED/CTR", 0, "SEED/CTR (1/2 K table)");
334  cout << "</TABLE>" << endl;
335 
336  BenchmarkAll2(t, hertz);
337 
338  cout << "Throughput Geometric Average: " << setiosflags(ios::fixed) << exp(logtotal/logcount) << endl;
339 
340  time_t endTime = time(NULL);
341  cout << "\nTest ended at " << asctime(localtime(&endTime));
342 #endif
343 }
used to pass byte array input as part of a NameValuePairs object
Definition: algparam.h:13
virtual void SetKey(const byte *key, size_t length, const NameValuePairs &params=g_nullNameValuePairs)
set or reset the key of this object
Definition: cryptlib.cpp:60
const char * Rounds()
int
Definition: argnames.h:18
interface for for one direction (encryption or decryption) of a stream cipher or block cipher mode wi...
Definition: cryptlib.h:627
virtual void GenerateBlock(byte *output, size_t size)
generate random array of bytes
Definition: cryptlib.cpp:264
virtual bool NeedsPrespecifiedDataLengths() const
if this function returns true, SpecifyDataLengths() must be called before attempting to input data ...
Definition: cryptlib.h:646
void ProcessString(byte *inoutString, size_t length)
same as ProcessData(inoutString, inoutString, length)
Definition: cryptlib.h:499
interface for buffered transformations
Definition: cryptlib.h:771
const char * TableSize()
int, in bytes
Definition: argnames.h:75
size_t Put(byte inByte, bool blocking=true)
input a byte for processing
Definition: cryptlib.h:785
virtual unsigned int OptimalBlockSize() const
returns the input block size that is most efficient for this cipher
Definition: cryptlib.h:481
keying interface for crypto algorithms that take byte strings as keys
Definition: cryptlib.h:347
const NameValuePairs & g_nullNameValuePairs
empty set of name-value pairs
Definition: cryptlib.cpp:40
interface for the data processing part of stream ciphers
Definition: cryptlib.h:470
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:16
virtual lword MaxMessageLength() const =0
the maximum length of encrypted data
interface for hash functions and data processing part of MACs
Definition: cryptlib.h:531
void SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength=0)
this function only needs to be called if NeedsPrespecifiedDataLengths() returns true ...
Definition: cryptlib.cpp:204
virtual void Update(const byte *input, size_t length)=0
process more input
interface for retrieving values given their names
Definition: cryptlib.h:225