1 // bench3.cpp - originally written and placed in the public domain by Wei Dai
2 // CryptoPP::Test namespace added by JW in February 2017
3
4 #include "cryptlib.h"
5 #include "bench.h"
6 #include "validate.h"
7
8 #include "cpu.h"
9 #include "factory.h"
10 #include "algparam.h"
11 #include "argnames.h"
12 #include "smartptr.h"
13 #include "stdcpp.h"
14
15 #include "pubkey.h"
16 #include "gfpcrypt.h"
17 #include "eccrypto.h"
18 #include "pkcspad.h"
19
20 #include "files.h"
21 #include "filters.h"
22 #include "hex.h"
23 #include "rsa.h"
24 #include "nr.h"
25 #include "dsa.h"
26 #include "luc.h"
27 #include "rw.h"
28 #include "ecp.h"
29 #include "ec2n.h"
30 #include "asn.h"
31 #include "dh.h"
32 #include "mqv.h"
33 #include "hmqv.h"
34 #include "fhmqv.h"
35 #include "xed25519.h"
36 #include "xtrcrypt.h"
37 #include "esign.h"
38 #include "pssr.h"
39 #include "oids.h"
40 #include "randpool.h"
41 #include "stdcpp.h"
42 #include "hrtimer.h"
43
44 #if CRYPTOPP_MSC_VERSION
45 # pragma warning(disable: 4505 4355)
46 #endif
47
48 NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)49 NAMESPACE_BEGIN(Test)
50
51 void BenchMarkEncryption(const char *name, PK_Encryptor &key, double timeTotal, bool pc = false)
52 {
53 unsigned int len = 16;
54 SecByteBlock plaintext(len), ciphertext(key.CiphertextLength(len));
55 Test::GlobalRNG().GenerateBlock(plaintext, len);
56
57 unsigned int i = 0;
58 double timeTaken;
59
60 ThreadUserTimer timer;
61 timer.StartTimer();
62
63 do
64 {
65 key.Encrypt(Test::GlobalRNG(), plaintext, len, ciphertext);
66 ++i; timeTaken = timer.ElapsedTimeAsDouble();
67 }
68 while (timeTaken < timeTotal);
69
70 std::string provider = key.AlgorithmProvider();
71 OutputResultOperations(name, provider.c_str(), "Encryption", pc, i, timeTaken);
72
73 if (!pc && key.GetMaterial().SupportsPrecomputation())
74 {
75 key.AccessMaterial().Precompute(16);
76 BenchMarkEncryption(name, key, timeTotal, true);
77 }
78 }
79
BenchMarkDecryption(const char * name,PK_Decryptor & priv,PK_Encryptor & pub,double timeTotal)80 void BenchMarkDecryption(const char *name, PK_Decryptor &priv, PK_Encryptor &pub, double timeTotal)
81 {
82 unsigned int len = 16;
83 SecByteBlock ciphertext(pub.CiphertextLength(len));
84 SecByteBlock plaintext(pub.MaxPlaintextLength(ciphertext.size()));
85 Test::GlobalRNG().GenerateBlock(plaintext, len);
86 pub.Encrypt(Test::GlobalRNG(), plaintext, len, ciphertext);
87
88 unsigned int i = 0;
89 double timeTaken;
90
91 ThreadUserTimer timer;
92 timer.StartTimer();
93
94 do
95 {
96 priv.Decrypt(Test::GlobalRNG(), ciphertext, ciphertext.size(), plaintext);
97 ++i; timeTaken = timer.ElapsedTimeAsDouble();
98 }
99 while (timeTaken < timeTotal);
100
101 std::string provider = priv.AlgorithmProvider();
102 OutputResultOperations(name, provider.c_str(), "Decryption", false, i, timeTaken);
103 }
104
BenchMarkSigning(const char * name,PK_Signer & key,double timeTotal,bool pc=false)105 void BenchMarkSigning(const char *name, PK_Signer &key, double timeTotal, bool pc=false)
106 {
107 unsigned int len = 16;
108 AlignedSecByteBlock message(len), signature(key.SignatureLength());
109 Test::GlobalRNG().GenerateBlock(message, len);
110
111 unsigned int i = 0;
112 double timeTaken;
113
114 ThreadUserTimer timer;
115 timer.StartTimer();
116
117 do
118 {
119 (void)key.SignMessage(Test::GlobalRNG(), message, len, signature);
120 ++i; timeTaken = timer.ElapsedTimeAsDouble();
121 }
122 while (timeTaken < timeTotal);
123
124 std::string provider = key.AlgorithmProvider();
125 OutputResultOperations(name, provider.c_str(), "Signature", pc, i, timeTaken);
126
127 if (!pc && key.GetMaterial().SupportsPrecomputation())
128 {
129 key.AccessMaterial().Precompute(16);
130 BenchMarkSigning(name, key, timeTotal, true);
131 }
132 }
133
BenchMarkVerification(const char * name,const PK_Signer & priv,PK_Verifier & pub,double timeTotal,bool pc=false)134 void BenchMarkVerification(const char *name, const PK_Signer &priv, PK_Verifier &pub, double timeTotal, bool pc=false)
135 {
136 unsigned int len = 16;
137 AlignedSecByteBlock message(len), signature(pub.SignatureLength());
138 Test::GlobalRNG().GenerateBlock(message, len);
139 priv.SignMessage(Test::GlobalRNG(), message, len, signature);
140
141 unsigned int i = 0;
142 double timeTaken;
143
144 ThreadUserTimer timer;
145 timer.StartTimer();
146
147 do
148 {
149 (void)pub.VerifyMessage(message, len, signature, signature.size());
150 ++i; timeTaken = timer.ElapsedTimeAsDouble();
151 }
152 while (timeTaken < timeTotal);
153
154 std::string provider = pub.AlgorithmProvider();
155 OutputResultOperations(name, provider.c_str(), "Verification", pc, i, timeTaken);
156
157 if (!pc && pub.GetMaterial().SupportsPrecomputation())
158 {
159 pub.AccessMaterial().Precompute(16);
160 BenchMarkVerification(name, priv, pub, timeTotal, true);
161 }
162 }
163
BenchMarkKeyGen(const char * name,SimpleKeyAgreementDomain & d,double timeTotal,bool pc=false)164 void BenchMarkKeyGen(const char *name, SimpleKeyAgreementDomain &d, double timeTotal, bool pc=false)
165 {
166 SecByteBlock priv(d.PrivateKeyLength()), pub(d.PublicKeyLength());
167
168 unsigned int i = 0;
169 double timeTaken;
170
171 ThreadUserTimer timer;
172 timer.StartTimer();
173
174 do
175 {
176 d.GenerateKeyPair(Test::GlobalRNG(), priv, pub);
177 ++i; timeTaken = timer.ElapsedTimeAsDouble();
178 }
179 while (timeTaken < timeTotal);
180
181 std::string provider = d.AlgorithmProvider();
182 OutputResultOperations(name, provider.c_str(), "Key-Pair Generation", pc, i, timeTaken);
183
184 if (!pc && d.GetMaterial().SupportsPrecomputation())
185 {
186 d.AccessMaterial().Precompute(16);
187 BenchMarkKeyGen(name, d, timeTotal, true);
188 }
189 }
190
BenchMarkKeyGen(const char * name,AuthenticatedKeyAgreementDomain & d,double timeTotal,bool pc=false)191 void BenchMarkKeyGen(const char *name, AuthenticatedKeyAgreementDomain &d, double timeTotal, bool pc=false)
192 {
193 SecByteBlock priv(d.EphemeralPrivateKeyLength()), pub(d.EphemeralPublicKeyLength());
194
195 unsigned int i = 0;
196 double timeTaken;
197
198 ThreadUserTimer timer;
199 timer.StartTimer();
200
201 do
202 {
203 d.GenerateEphemeralKeyPair(Test::GlobalRNG(), priv, pub);
204 ++i; timeTaken = timer.ElapsedTimeAsDouble();
205 }
206 while (timeTaken < timeTotal);
207
208 std::string provider = d.AlgorithmProvider();
209 OutputResultOperations(name, provider.c_str(), "Key-Pair Generation", pc, i, timeTaken);
210
211 if (!pc && d.GetMaterial().SupportsPrecomputation())
212 {
213 d.AccessMaterial().Precompute(16);
214 BenchMarkKeyGen(name, d, timeTotal, true);
215 }
216 }
217
BenchMarkAgreement(const char * name,SimpleKeyAgreementDomain & d,double timeTotal,bool pc=false)218 void BenchMarkAgreement(const char *name, SimpleKeyAgreementDomain &d, double timeTotal, bool pc=false)
219 {
220 SecByteBlock priv1(d.PrivateKeyLength()), priv2(d.PrivateKeyLength());
221 SecByteBlock pub1(d.PublicKeyLength()), pub2(d.PublicKeyLength());
222 d.GenerateKeyPair(Test::GlobalRNG(), priv1, pub1);
223 d.GenerateKeyPair(Test::GlobalRNG(), priv2, pub2);
224 SecByteBlock val(d.AgreedValueLength());
225
226 unsigned int i = 0;
227 double timeTaken;
228
229 ThreadUserTimer timer;
230 timer.StartTimer();
231
232 do
233 {
234 d.Agree(val, priv1, pub2);
235 d.Agree(val, priv2, pub1);
236 i+=2; timeTaken = timer.ElapsedTimeAsDouble();
237 }
238 while (timeTaken < timeTotal);
239
240 std::string provider = d.AlgorithmProvider();
241 OutputResultOperations(name, provider.c_str(), "Key Agreement", pc, i, timeTaken);
242 }
243
BenchMarkAgreement(const char * name,AuthenticatedKeyAgreementDomain & d,double timeTotal,bool pc=false)244 void BenchMarkAgreement(const char *name, AuthenticatedKeyAgreementDomain &d, double timeTotal, bool pc=false)
245 {
246 SecByteBlock spriv1(d.StaticPrivateKeyLength()), spriv2(d.StaticPrivateKeyLength());
247 SecByteBlock epriv1(d.EphemeralPrivateKeyLength()), epriv2(d.EphemeralPrivateKeyLength());
248 SecByteBlock spub1(d.StaticPublicKeyLength()), spub2(d.StaticPublicKeyLength());
249 SecByteBlock epub1(d.EphemeralPublicKeyLength()), epub2(d.EphemeralPublicKeyLength());
250 d.GenerateStaticKeyPair(Test::GlobalRNG(), spriv1, spub1);
251 d.GenerateStaticKeyPair(Test::GlobalRNG(), spriv2, spub2);
252 d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv1, epub1);
253 d.GenerateEphemeralKeyPair(Test::GlobalRNG(), epriv2, epub2);
254 SecByteBlock val(d.AgreedValueLength());
255
256 unsigned int i = 0;
257 double timeTaken;
258
259 ThreadUserTimer timer;
260 timer.StartTimer();
261
262 do
263 {
264 d.Agree(val, spriv1, epriv1, spub2, epub2);
265 d.Agree(val, spriv2, epriv2, spub1, epub1);
266 i+=2; timeTaken = timer.ElapsedTimeAsDouble();
267 }
268 while (timeTaken < timeTotal);
269
270 std::string provider = d.AlgorithmProvider();
271 OutputResultOperations(name, provider.c_str(), "Key Agreement", pc, i, timeTaken);
272 }
273
274 template <class SCHEME>
BenchMarkCrypto(const char * filename,const char * name,double timeTotal)275 void BenchMarkCrypto(const char *filename, const char *name, double timeTotal)
276 {
277 FileSource f(DataDir(filename).c_str(), true, new HexDecoder);
278 typename SCHEME::Decryptor priv(f);
279 typename SCHEME::Encryptor pub(priv);
280 BenchMarkEncryption(name, pub, timeTotal);
281 BenchMarkDecryption(name, priv, pub, timeTotal);
282 }
283
284 template <class SCHEME>
BenchMarkSignature(const char * filename,const char * name,double timeTotal)285 void BenchMarkSignature(const char *filename, const char *name, double timeTotal)
286 {
287 FileSource f(DataDir(filename).c_str(), true, new HexDecoder);
288 typename SCHEME::Signer priv(f);
289 typename SCHEME::Verifier pub(priv);
290 BenchMarkSigning(name, priv, timeTotal);
291 BenchMarkVerification(name, priv, pub, timeTotal);
292 }
293
294 template <class D>
BenchMarkKeyAgreement(const char * filename,const char * name,double timeTotal)295 void BenchMarkKeyAgreement(const char *filename, const char *name, double timeTotal)
296 {
297 FileSource f(DataDir(filename).c_str(), true, new HexDecoder);
298 D d(f);
299 BenchMarkKeyGen(name, d, timeTotal);
300 BenchMarkAgreement(name, d, timeTotal);
301 }
302
BenchmarkPublicKeyAlgorithms(double t,double hertz)303 void BenchmarkPublicKeyAlgorithms(double t, double hertz)
304 {
305 g_allocatedTime = t;
306 g_hertz = hertz;
307
308 const char *mco;
309 if (g_hertz > 1.0f)
310 mco = "<TH>Megacycles/Operation";
311 else
312 mco = "";
313
314 std::cout << "\n<TABLE>";
315 std::cout << "\n<COLGROUP><COL style=\"text-align: left;\"><COL style=";
316 std::cout << "\"text-align: right;\"><COL style=\"text-align: right;\">";
317 std::cout << "\n<THEAD style=\"background: #F0F0F0\">";
318 std::cout << "\n<TR><TH>Operation<TH>Milliseconds/Operation" << mco;
319
320 std::cout << "\n<TBODY style=\"background: white;\">";
321 {
322 BenchMarkCrypto<RSAES<OAEP<SHA1> > >("TestData/rsa1024.dat", "RSA 1024", t);
323 BenchMarkCrypto<LUCES<OAEP<SHA1> > >("TestData/luc1024.dat", "LUC 1024", t);
324 BenchMarkCrypto<DLIES<> >("TestData/dlie1024.dat", "DLIES 1024", t);
325 BenchMarkCrypto<LUC_IES<> >("TestData/lucc512.dat", "LUCELG 512", t);
326 }
327
328 std::cout << "\n<TBODY style=\"background: yellow;\">";
329 {
330 BenchMarkCrypto<RSAES<OAEP<SHA1> > >("TestData/rsa2048.dat", "RSA 2048", t);
331 BenchMarkCrypto<LUCES<OAEP<SHA1> > >("TestData/luc2048.dat", "LUC 2048", t);
332 BenchMarkCrypto<DLIES<> >("TestData/dlie2048.dat", "DLIES 2048", t);
333 BenchMarkCrypto<LUC_IES<> >("TestData/lucc1024.dat", "LUCELG 1024", t);
334 }
335
336 std::cout << "\n<TBODY style=\"background: white;\">";
337 {
338 BenchMarkSignature<RSASS<PSSR, SHA1> >("TestData/rsa1024.dat", "RSA 1024", t);
339 BenchMarkSignature<RWSS<PSSR, SHA1> >("TestData/rw1024.dat", "RW 1024", t);
340 BenchMarkSignature<LUCSS<PSSR, SHA1> >("TestData/luc1024.dat", "LUC 1024", t);
341 BenchMarkSignature<NR<SHA1> >("TestData/nr1024.dat", "NR 1024", t);
342 BenchMarkSignature<DSA>("TestData/dsa1024.dat", "DSA 1024", t);
343 BenchMarkSignature<LUC_HMP<SHA1> >("TestData/lucs512.dat", "LUC-HMP 512", t);
344 BenchMarkSignature<ESIGN<SHA1> >("TestData/esig1023.dat", "ESIGN 1023", t);
345 BenchMarkSignature<ESIGN<SHA1> >("TestData/esig1536.dat", "ESIGN 1536", t);
346 }
347
348 std::cout << "\n<TBODY style=\"background: yellow;\">";
349 {
350 BenchMarkSignature<RSASS<PSSR, SHA1> >("TestData/rsa2048.dat", "RSA 2048", t);
351 BenchMarkSignature<RWSS<PSSR, SHA1> >("TestData/rw2048.dat", "RW 2048", t);
352 BenchMarkSignature<LUCSS<PSSR, SHA1> >("TestData/luc2048.dat", "LUC 2048", t);
353 BenchMarkSignature<NR<SHA1> >("TestData/nr2048.dat", "NR 2048", t);
354 BenchMarkSignature<LUC_HMP<SHA1> >("TestData/lucs1024.dat", "LUC-HMP 1024", t);
355 BenchMarkSignature<ESIGN<SHA1> >("TestData/esig2046.dat", "ESIGN 2046", t);
356 }
357
358 std::cout << "\n<TBODY style=\"background: white;\">";
359 {
360 BenchMarkKeyAgreement<XTR_DH>("TestData/xtrdh171.dat", "XTR-DH 171", t);
361 BenchMarkKeyAgreement<XTR_DH>("TestData/xtrdh342.dat", "XTR-DH 342", t);
362 BenchMarkKeyAgreement<DH>("TestData/dh1024.dat", "DH 1024", t);
363 BenchMarkKeyAgreement<DH>("TestData/dh2048.dat", "DH 2048", t);
364 BenchMarkKeyAgreement<LUC_DH>("TestData/lucd512.dat", "LUCDIF 512", t);
365 BenchMarkKeyAgreement<LUC_DH>("TestData/lucd1024.dat", "LUCDIF 1024", t);
366 BenchMarkKeyAgreement<MQV>("TestData/mqv1024.dat", "MQV 1024", t);
367 BenchMarkKeyAgreement<MQV>("TestData/mqv2048.dat", "MQV 2048", t);
368 }
369
370 std::cout << "\n</TABLE>" << std::endl;
371 }
372
BenchmarkEllipticCurveAlgorithms(double t,double hertz)373 void BenchmarkEllipticCurveAlgorithms(double t, double hertz)
374 {
375 g_allocatedTime = t;
376 g_hertz = hertz;
377
378 const char *mco;
379 if (g_hertz > 1.0f)
380 mco = "<TH>Megacycles/Operation";
381 else
382 mco = "";
383
384 std::cout << "\n<TABLE>";
385 std::cout << "\n<COLGROUP><COL style=\"text-align: left;\"><COL style=";
386 std::cout << "\"text-align: right;\"><COL style=\"text-align: right;\">";
387 std::cout << "\n<THEAD style=\"background: #F0F0F0\">";
388 std::cout << "\n<TR><TH>Operation<TH>Milliseconds/Operation" << mco;
389
390 std::cout << "\n<TBODY style=\"background: white;\">";
391 {
392 ed25519::Signer sign(Test::GlobalRNG());
393 ed25519::Verifier verify(sign);
394 x25519 agree(Test::GlobalRNG());
395
396 BenchMarkSigning("ed25519", sign, t);
397 BenchMarkVerification("ed25519", sign, verify, t);
398 BenchMarkKeyGen("x25519", agree, t);
399 BenchMarkAgreement("x25519", agree, t);
400 }
401
402 #if 0
403 std::cout << "\n<TBODY style=\"background: yellow;\">";
404 {
405 BenchMarkKeyAgreement<ECMQV160>("TestData/mqv160.dat", "MQV P-160", t);
406 BenchMarkKeyAgreement<ECMQV256>("TestData/mqv256.dat", "MQV P-256", t);
407 BenchMarkKeyAgreement<ECMQV384>("TestData/mqv384.dat", "MQV P-384", t);
408 BenchMarkKeyAgreement<ECMQV512>("TestData/mqv512.dat", "MQV P-521", t);
409
410 BenchMarkKeyAgreement<ECHMQV160>("TestData/hmqv160.dat", "HMQV P-160", t);
411 BenchMarkKeyAgreement<ECHMQV256>("TestData/hmqv256.dat", "HMQV P-256", t);
412 BenchMarkKeyAgreement<ECHMQV384>("TestData/hmqv384.dat", "HMQV P-384", t);
413 BenchMarkKeyAgreement<ECHMQV512>("TestData/hmqv512.dat", "HMQV P-521", t);
414
415 BenchMarkKeyAgreement<ECFHMQV160>("TestData/fhmqv160.dat", "FHMQV P-160", t);
416 BenchMarkKeyAgreement<ECFHMQV256>("TestData/fhmqv256.dat", "FHMQV P-256", t);
417 BenchMarkKeyAgreement<ECFHMQV384>("TestData/fhmqv384.dat", "FHMQV P-384", t);
418 BenchMarkKeyAgreement<ECFHMQV512>("TestData/fhmqv512.dat", "FHMQV P-521", t);
419 }
420 #endif
421
422 std::cout << "\n<TBODY style=\"background: yellow;\">";
423 {
424 ECIES<ECP>::Decryptor cpriv(Test::GlobalRNG(), ASN1::secp256k1());
425 ECIES<ECP>::Encryptor cpub(cpriv);
426 ECDSA<ECP, SHA1>::Signer spriv(cpriv);
427 ECDSA<ECP, SHA1>::Verifier spub(spriv);
428 ECDSA_RFC6979<ECP, SHA1>::Signer spriv2(cpriv);
429 ECDSA_RFC6979<ECP, SHA1>::Verifier spub2(spriv2);
430 ECGDSA<ECP, SHA1>::Signer spriv3(Test::GlobalRNG(), ASN1::secp256k1());
431 ECGDSA<ECP, SHA1>::Verifier spub3(spriv3);
432 ECDH<ECP>::Domain ecdhc(ASN1::secp256k1());
433 ECMQV<ECP>::Domain ecmqvc(ASN1::secp256k1());
434
435 BenchMarkEncryption("ECIES over GF(p) 256", cpub, t);
436 BenchMarkDecryption("ECIES over GF(p) 256", cpriv, cpub, t);
437 BenchMarkSigning("ECDSA over GF(p) 256", spriv, t);
438 BenchMarkVerification("ECDSA over GF(p) 256", spriv, spub, t);
439 BenchMarkSigning("ECDSA-RFC6979 over GF(p) 256", spriv2, t);
440 BenchMarkVerification("ECDSA-RFC6979 over GF(p) 256", spriv2, spub2, t);
441 BenchMarkSigning("ECGDSA over GF(p) 256", spriv3, t);
442 BenchMarkVerification("ECGDSA over GF(p) 256", spriv3, spub3, t);
443 BenchMarkKeyGen("ECDHC over GF(p) 256", ecdhc, t);
444 BenchMarkAgreement("ECDHC over GF(p) 256", ecdhc, t);
445 BenchMarkKeyGen("ECMQVC over GF(p) 256", ecmqvc, t);
446 BenchMarkAgreement("ECMQVC over GF(p) 256", ecmqvc, t);
447 }
448
449 std::cout << "\n<TBODY style=\"background: white;\">";
450 {
451 ECIES<EC2N>::Decryptor cpriv(Test::GlobalRNG(), ASN1::sect233r1());
452 ECIES<EC2N>::Encryptor cpub(cpriv);
453 ECDSA<EC2N, SHA1>::Signer spriv(cpriv);
454 ECDSA<EC2N, SHA1>::Verifier spub(spriv);
455 ECDSA_RFC6979<EC2N, SHA1>::Signer spriv2(cpriv);
456 ECDSA_RFC6979<EC2N, SHA1>::Verifier spub2(spriv2);
457 ECGDSA<EC2N, SHA1>::Signer spriv3(Test::GlobalRNG(), ASN1::sect233r1());
458 ECGDSA<EC2N, SHA1>::Verifier spub3(spriv3);
459 ECDH<EC2N>::Domain ecdhc(ASN1::sect233r1());
460 ECMQV<EC2N>::Domain ecmqvc(ASN1::sect233r1());
461
462 BenchMarkEncryption("ECIES over GF(2^n) 233", cpub, t);
463 BenchMarkDecryption("ECIES over GF(2^n) 233", cpriv, cpub, t);
464 BenchMarkSigning("ECDSA over GF(2^n) 233", spriv, t);
465 BenchMarkVerification("ECDSA over GF(2^n) 233", spriv, spub, t);
466 BenchMarkSigning("ECDSA-RFC6979 over GF(2^n) 233", spriv2, t);
467 BenchMarkVerification("ECDSA-RFC6979 over GF(2^n) 233", spriv2, spub2, t);
468 BenchMarkSigning("ECGDSA over GF(2^n) 233", spriv3, t);
469 BenchMarkVerification("ECGDSA over GF(2^n) 233", spriv3, spub3, t);
470 BenchMarkKeyGen("ECDHC over GF(2^n) 233", ecdhc, t);
471 BenchMarkAgreement("ECDHC over GF(2^n) 233", ecdhc, t);
472 BenchMarkKeyGen("ECMQVC over GF(2^n) 233", ecmqvc, t);
473 BenchMarkAgreement("ECMQVC over GF(2^n) 233", ecmqvc, t);
474 }
475
476 std::cout << "\n</TABLE>" << std::endl;
477 }
478
479 NAMESPACE_END // Test
480 NAMESPACE_END // CryptoPP
481