什么是最快的 SHA1 实现?
What is the fastest SHA1 implementation?
我正在寻找最快的 SHA1 实现,因为我必须对它进行数百万次计算。我试过 boost::uuids::detail::sha1 and OpenSSL SHA1 and I find OpenSSL 2.5 times faster than boost. I also checked Crypto++ 比其他两个慢得多。这是我检查他们表现的方法:
OpenSSL SHA1:
#include "openssl/sha.h"
void sha1_ossl (const unsigned char* data) {
unsigned char hash[20];
for (long i=0; i<100000000; ++i) {
SHA1(data, 64, hash);
if ((unsigned int)hash[0]==0 && (unsigned int)hash[1]==0 && (unsigned int)hash[2]==0 && (unsigned int)hash[3]==0)
break;
}
}
提升::SHA1:
#include <boost/uuid/detail/sha1.hpp>
void sha1_boost (const unsigned char* data) {
boost::uuids::detail::sha1 sha1;
unsigned hash[5];
for (long i=0; i<100000000; ++i) {
sha1.process_bytes(data, 64);
sha1.get_digest(hash);
sha1.reset();
if (hash[0]==0) break;
}
}
加密PP::SHA1:
#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
void sha1_cryptoPP (const unsigned char* data) {
std::string data_s (reinterpret_cast<char const*>(data));
std::string hash_hex;
CryptoPP::SHA1 sha1;
for (long i=0; i<100000000; ++i) {
CryptoPP::StringSource ss(data_s, true, new CryptoPP::HashFilter(sha1, new CryptoPP::HexEncoder(new CryptoPP::StringSink(hash_hex))));
if (hash_hex.starts_with("00000000")) break;
}
}
然后我用随机数据测试这些函数:
int main() {
const unsigned char data[65] = "tJQVfvcjGMNIvJfowXBjmSRcKtSjCcyQvaAdakfEJtgSNZHnOHCjkzGFwngiLFPm";
sha1_boost (data);
sha1_ossl (data);
sha1_cryptoPP (data);
}
性能结果
我用g++ -O3 -std=c++2a
编译了所有的代码得到如下结果。我发现 OpenSSL 比其他实现更快,而 Crypto++ 最慢:
问题
- 最快的 SHA1 实现是什么?
- 如何改进我的 Crypto++ 功能?
感谢任何有助于提高性能的反馈。
我最后的实验证实 openssl 是几个中最快的(包括 Crypto++ 和一些丢失 single-source C 实现,我忘记了哪些)
回复:问题的 code-review 类型部分:
boost“实现”来自详细命名空间,不应依赖。
CryptoPP 可能会受益于使用过程接口而不是每次都动态组合管道。具体来说,您不应该转换为字符串来检查摘要的前 n 个字节。由于重复分配,这可能是运行时的主要部分。
遵守程序接口还可以让您使用 reset/clear 成员(引用记忆)
if ((unsigned int)hash[0] == 0 && (unsigned int)hash[1] == 0 &&
(unsigned int)hash[2] == 0 && (unsigned int)hash[3] == 0)
break;
本来应该很简单
if (!(hash[0] || hash[1] || hash[2] || hash[3]))
break;
甚至
if (!std::any_of(hash+0, hash+4, std::identity{}))
break;
改进的基准代码
结合以上的一些和更多(主要围绕良好的风格,避免指针错误,显示有效的迭代并允许 dump
检查摘要的准确性):
#include "openssl/sha.h"
#include <boost/uuid/detail/sha1.hpp>
#include <algorithm>
#include <iostream>
#include <iomanip>
using byte = unsigned char;
#ifndef ONLINE_DEMO
auto constexpr iterations = 100'000'000;
#else
auto constexpr iterations = 10000;
#endif
static void dump(byte const (&a)[20]) {
for (unsigned b : a) {
std::cout << std::setw(2) << std::setfill('0') << std::hex << b;
}
std::cout << std::dec << std::endl;
}
static void dump(uint32_t const (&a)[5]) {
for (auto b : a) {
std::cout << std::setw(8) << std::setfill('0') << std::hex << b;
}
std::cout << std::dec << std::endl;
}
long sha1_ossl(std::string_view data) {
byte hash[20];
for (long i = 0; i < iterations; ++i) {
SHA1(reinterpret_cast<byte const*>(data.data()), data.size(), hash);
//dump(hash);
if (!std::any_of(hash+0, hash+4, std::identity{}))
return i;
}
return iterations;
}
long sha1_boost(std::string_view data) {
boost::uuids::detail::sha1 sha1;
uint32_t hash[5];
for (long i = 0; i < iterations; ++i) {
sha1.process_bytes(reinterpret_cast<byte const*>(data.data()), data.size());
sha1.get_digest(hash);
sha1.reset();
//dump(hash);
if (hash[0] == 0)
return i;
}
return iterations;
}
#ifndef ONLINE_DEMO
#include <cryptopp/hex.h>
#include <cryptopp/sha.h>
long sha1_cryptoPP(std::string_view data) {
byte digest[20];
CryptoPP::SHA1 sha1;
for (long i = 0; i < iterations; ++i) {
sha1.Restart();
sha1.Update(reinterpret_cast<byte const*>(data.data()), data.size());
sha1.Final(digest);
//dump(digest);
if (!std::any_of(digest+0, digest+4, std::identity{}))
return i;
}
return iterations;
}
#endif
#include <chrono>
using namespace std::chrono_literals;
int main() {
static auto now = std::chrono::high_resolution_clock::now;
constexpr static std::string_view data =
"tJQVfvcjGMNIvJfowXBjmSRcKtSjCcyQvaAdakfEJtgSNZHnOHCjkzGFwngiLFPm";
auto timed = [](auto caption, auto f) {
auto const start = now();
auto n = f(data);
std::cout << caption << ": " << n << " in " << (now()-start)/1.0ms << "ms\n";
};
timed("sha1_boost", sha1_boost);
timed("sha1_ossl", sha1_ossl);
#ifndef ONLINE_DEMO
timed("sha1_cryptoPP", sha1_cryptoPP);
#endif
}
打印:
sha1_boost: 100000000 in 85660.5ms
sha1_ossl: 100000000 in 24652.6ms
sha1_cryptoPP: 100000000 in 34921.3ms
或在线(那里没有 Crypto++):
sha1_boost: 10000 in 8.71938ms
sha1_ossl: 10000 in 2.32025ms
这是一个显着的进步,但同样是赢家。
我正在寻找最快的 SHA1 实现,因为我必须对它进行数百万次计算。我试过 boost::uuids::detail::sha1 and OpenSSL SHA1 and I find OpenSSL 2.5 times faster than boost. I also checked Crypto++ 比其他两个慢得多。这是我检查他们表现的方法:
OpenSSL SHA1:
#include "openssl/sha.h"
void sha1_ossl (const unsigned char* data) {
unsigned char hash[20];
for (long i=0; i<100000000; ++i) {
SHA1(data, 64, hash);
if ((unsigned int)hash[0]==0 && (unsigned int)hash[1]==0 && (unsigned int)hash[2]==0 && (unsigned int)hash[3]==0)
break;
}
}
提升::SHA1:
#include <boost/uuid/detail/sha1.hpp>
void sha1_boost (const unsigned char* data) {
boost::uuids::detail::sha1 sha1;
unsigned hash[5];
for (long i=0; i<100000000; ++i) {
sha1.process_bytes(data, 64);
sha1.get_digest(hash);
sha1.reset();
if (hash[0]==0) break;
}
}
加密PP::SHA1:
#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
void sha1_cryptoPP (const unsigned char* data) {
std::string data_s (reinterpret_cast<char const*>(data));
std::string hash_hex;
CryptoPP::SHA1 sha1;
for (long i=0; i<100000000; ++i) {
CryptoPP::StringSource ss(data_s, true, new CryptoPP::HashFilter(sha1, new CryptoPP::HexEncoder(new CryptoPP::StringSink(hash_hex))));
if (hash_hex.starts_with("00000000")) break;
}
}
然后我用随机数据测试这些函数:
int main() {
const unsigned char data[65] = "tJQVfvcjGMNIvJfowXBjmSRcKtSjCcyQvaAdakfEJtgSNZHnOHCjkzGFwngiLFPm";
sha1_boost (data);
sha1_ossl (data);
sha1_cryptoPP (data);
}
性能结果
我用g++ -O3 -std=c++2a
编译了所有的代码得到如下结果。我发现 OpenSSL 比其他实现更快,而 Crypto++ 最慢:
问题
- 最快的 SHA1 实现是什么?
- 如何改进我的 Crypto++ 功能?
感谢任何有助于提高性能的反馈。
我最后的实验证实 openssl 是几个中最快的(包括 Crypto++ 和一些丢失 single-source C 实现,我忘记了哪些)
回复:问题的 code-review 类型部分:
boost“实现”来自详细命名空间,不应依赖。
CryptoPP 可能会受益于使用过程接口而不是每次都动态组合管道。具体来说,您不应该转换为字符串来检查摘要的前 n 个字节。由于重复分配,这可能是运行时的主要部分。
遵守程序接口还可以让您使用 reset/clear 成员(引用记忆)
if ((unsigned int)hash[0] == 0 && (unsigned int)hash[1] == 0 &&
(unsigned int)hash[2] == 0 && (unsigned int)hash[3] == 0)
break;
本来应该很简单
if (!(hash[0] || hash[1] || hash[2] || hash[3]))
break;
甚至
if (!std::any_of(hash+0, hash+4, std::identity{}))
break;
改进的基准代码
结合以上的一些和更多(主要围绕良好的风格,避免指针错误,显示有效的迭代并允许 dump
检查摘要的准确性):
#include "openssl/sha.h"
#include <boost/uuid/detail/sha1.hpp>
#include <algorithm>
#include <iostream>
#include <iomanip>
using byte = unsigned char;
#ifndef ONLINE_DEMO
auto constexpr iterations = 100'000'000;
#else
auto constexpr iterations = 10000;
#endif
static void dump(byte const (&a)[20]) {
for (unsigned b : a) {
std::cout << std::setw(2) << std::setfill('0') << std::hex << b;
}
std::cout << std::dec << std::endl;
}
static void dump(uint32_t const (&a)[5]) {
for (auto b : a) {
std::cout << std::setw(8) << std::setfill('0') << std::hex << b;
}
std::cout << std::dec << std::endl;
}
long sha1_ossl(std::string_view data) {
byte hash[20];
for (long i = 0; i < iterations; ++i) {
SHA1(reinterpret_cast<byte const*>(data.data()), data.size(), hash);
//dump(hash);
if (!std::any_of(hash+0, hash+4, std::identity{}))
return i;
}
return iterations;
}
long sha1_boost(std::string_view data) {
boost::uuids::detail::sha1 sha1;
uint32_t hash[5];
for (long i = 0; i < iterations; ++i) {
sha1.process_bytes(reinterpret_cast<byte const*>(data.data()), data.size());
sha1.get_digest(hash);
sha1.reset();
//dump(hash);
if (hash[0] == 0)
return i;
}
return iterations;
}
#ifndef ONLINE_DEMO
#include <cryptopp/hex.h>
#include <cryptopp/sha.h>
long sha1_cryptoPP(std::string_view data) {
byte digest[20];
CryptoPP::SHA1 sha1;
for (long i = 0; i < iterations; ++i) {
sha1.Restart();
sha1.Update(reinterpret_cast<byte const*>(data.data()), data.size());
sha1.Final(digest);
//dump(digest);
if (!std::any_of(digest+0, digest+4, std::identity{}))
return i;
}
return iterations;
}
#endif
#include <chrono>
using namespace std::chrono_literals;
int main() {
static auto now = std::chrono::high_resolution_clock::now;
constexpr static std::string_view data =
"tJQVfvcjGMNIvJfowXBjmSRcKtSjCcyQvaAdakfEJtgSNZHnOHCjkzGFwngiLFPm";
auto timed = [](auto caption, auto f) {
auto const start = now();
auto n = f(data);
std::cout << caption << ": " << n << " in " << (now()-start)/1.0ms << "ms\n";
};
timed("sha1_boost", sha1_boost);
timed("sha1_ossl", sha1_ossl);
#ifndef ONLINE_DEMO
timed("sha1_cryptoPP", sha1_cryptoPP);
#endif
}
打印:
sha1_boost: 100000000 in 85660.5ms
sha1_ossl: 100000000 in 24652.6ms
sha1_cryptoPP: 100000000 in 34921.3ms
或在线(那里没有 Crypto++):
sha1_boost: 10000 in 8.71938ms
sha1_ossl: 10000 in 2.32025ms
这是一个显着的进步,但同样是赢家。