我正在从事一个项目,作为项目的一部分,我必须大致模拟比特币工作量证明的计算。这涉及在固定的“ BlockHash”字符串和一个32位int随机数的串联上迭代计算SHA256两次,每次迭代均递增。如果计算的哈希值小于“ TargetHash”字符串,我们将中断循环并打印现时值。
我正在尝试比较两个顺序的实现,一个使用OpenSSL的SHA256实现使用C ++编写,另一个使用JDK的内部SHA256实现使用Java编写。我原以为OpenSSL的实现要比JDK快得多,但正相反。
这是我的Java代码:
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SHA256 {
/**
* convert byte[] to hex string
*
* @param hash
* @return hex string
*/
private static String bytesToHex(byte[] hash) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
/**
* get a sha256 of the input string
*
* @param inputString
* @return resulting hash in hex string
*/
public static String SHA256(String inputString) {
try {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
return bytesToHex(sha256.digest(inputString.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException ex) {
System.err.println(ex.toString());
return null;
}
}
public static void main(String[] args){
String blockHash = SHA256("Some random string to generate a block hash.");
System.out.println("blockHash: " + blockHash);
String targetHash = "000000938023b712892a41e8438e3ff2242a68747105de0395826f60b38d88dc";
String tmp_hash="undefined";
int nonce = 0;
for(nonce=Integer.MIN_VALUE; nonce<=Integer.MAX_VALUE; nonce++) {
tmp_hash = SHA256(SHA256(blockHash+String.valueOf(nonce)));
if(targetHash.compareTo(tmp_hash)>0)
break;
}
System.out.println("Resulting Hash: " + tmp_hash);
System.out.println("Nonce:" + nonce);
}
}
这是我的C ++实现:
#include <iostream>
#include <climits>
#include <cstring>
#include <sstream>
#include <string>
#include <iomanip>
#include "format.h"
using namespace std;
#include <openssl/sha.h>
string sha256(const string str)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
stringstream ss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
ss << hex << setw(2) << setfill('0') << (int)hash[i];
}
return ss.str();
}
int main(int argc, char *argv[])
{
string input = "Some random string to generate a block hash.";
string blockHash = sha256(input);
cout << "blockHash: " << blockHash << endl;
string targetHash = "000000938023b712892a41e8438e3ff2242a68747105de0395826f60b38d88dc";
string tmp_hash="undefined";
int nonce = 0;
for(nonce = INT_MIN; nonce <= INT_MAX; nonce++){
tmp_hash = sha256(sha256(fmt::format("{}{}", blockHash, nonce)));
if(strcmp(tmp_hash.c_str(), targetHash.c_str()) < 0)
break;
}
cout<<"Resulting Hash: "<<tmp_hash<<endl;
cout<<"Nonce: "<<nonce<<endl;
return 0;
}
使用linux'time'实用程序来测量运行时的输出:
javac SHA256.java
time java SHA256
blockHash: 596143a6a70a23c86e4b218afeb05d151ed45a39e96368e213d17e0a491d894a
Resulting Hash: 0000008ce61c628ffb00b6668687504fd5d44da0a57adb40d6ff59f8e4af0a4a
Nonce:-2135751361
real 0m22.258s
user 0m22.977s
sys 0m0.097s
g++ -O2 -DFMT_HEADER_ONLY main.cpp -lcrypto -lssl
time ./a.out
blockHash: 596143a6a70a23c86e4b218afeb05d151ed45a39e96368e213d17e0a491d894a
Resulting Hash: 0000008ce61c628ffb00b6668687504fd5d44da0a57adb40d6ff59f8e4af0a4a
Nonce: -2135751361
real 0m35.703s
user 0m35.693s
sys 0m0.005s
这只是用于简单的TargetHash,对于更困难的TargetHash,差异更大。我很确定,这里的openssl sha256实现不是瓶颈,还有其他问题,但是对于C ++来说,我不确定是什么。我之前使用过to_string(nonce)和s1.compare(s2),我将它们替换为fmt :: format和strcmp,因为它们速度更快,但仍然只能获得几秒钟的时间。任何想法将不胜感激。
您的C ++代码的瓶颈是您的自定义bytes_to_string函数。循环调用stringstream函数只会降低性能。
您可能想在另一个问题上查看此answer。