java - C++ openssl SHA256 运行速度比 JDK SHA256 实现慢

标签 java c++ openssl bitcoin sha256

我正在做一个项目,作为项目的一部分,我必须粗略地模拟比特币工作量证明计算。这涉及在固定“BlockHash”字符串和每次迭代递增的 32 位 int nonce 的串联上迭代计算 SHA256 两次。如果计算出的哈希值小于“TargetHash”字符串,我们将中断循环并打印随机数值。

我正在尝试比较两个顺序实现,一个是使用 C++ 使用 OpenSSL 的 SHA256 实现编写的,另一个是使用 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,对于更难的,差别就更大了。我很确定这里的 openssl sha256 实现不是瓶颈,其他东西是,但作为 C++ 的新手我不确定是什么。我之前使用的是 to_string(nonce) 和 s1.compare(s2),我将其替换为 fmt::format 和 strcmp,因为它们速度更快,但仍然只能获得几秒钟的时间。任何想法将不胜感激。

最佳答案

您的 C++ 代码的瓶颈是您的自定义 bytes_to_string 函数。在循环中调用 stringstream 函数只会影响性能。

你可能想看看这个 answer 到另一个问题。


用以下代码片段替换字符串流函数。它更快,因为它直接操作字符串内存。

static const char characters[] = "0123456789ABCDEF";
std::string result (SHA256_DIGEST_LENGTH * 2, ' ');
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
    result[2*i] = characters[(unsigned int) hash[i] >> 4];
    result[2*i+1] = characters[(unsigned int) hash[i] & 0x0F];
}
return result;

关于java - C++ openssl SHA256 运行速度比 JDK SHA256 实现慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58613142/

相关文章:

PHP 在连接到 MySql 时忽略 ssl 证书

java - 如何使用javaFX Canvas绘制图像图案

java - else 语句会减慢编译时间/运行速度吗? (在可以避免的情况下)

java - POST 请求正在调用 doGet 方法

c# - 在 C# 中复制 Java 的 DecimalFormat

c++ - 如何在 JUCE 项目中获得 "go to definition"?

c++ - bool 表达式习语中的这个字符串文字是什么?

c++ - 如何开始使用 z3

c++ - 单个应用程序可以是服务器和客户端并查询本身

linux - 如何使用 openssl 识别证书的 RSA 签名中使用的填充方案?