如何提高C++中merkle根计算的速度?

2024-01-07

我正在尝试尽可能优化默克尔根计算。到目前为止,我用 Python 实现了它,结果是这个问题 https://stackoverflow.com/questions/67355203/how-to-improve-the-speed-of-merkle-root-calculation以及用 C++ 重写它的建议。

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>

#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>



std::vector<unsigned char> double_sha256(std::vector<unsigned char> a, std::vector<unsigned char> b)
{
    unsigned char inp[64];
    int j=0;
    for (int i=0; i<32; i++)
    {
        inp[j] = a[i];
        j++;
    }
    for (int i=0; i<32; i++)
    {
        inp[j] = b[i];
        j++;
    }

    const EVP_MD *md_algo = EVP_sha256();
    unsigned int md_len = EVP_MD_size(md_algo);
    std::vector<unsigned char> out( md_len );
    EVP_Digest(inp, 64, out.data(), &md_len, md_algo, nullptr);
    EVP_Digest(out.data(), md_len, out.data(), &md_len, md_algo, nullptr);
    return out;
}

std::vector<std::vector<unsigned char> > calculate_merkle_root(std::vector<std::vector<unsigned char> > inp_list)
{
   std::vector<std::vector<unsigned char> > out;
   int len = inp_list.size();
   if (len == 1)
   {
        out.push_back(inp_list[0]);
        return out;
   }
   for (int i=0; i<len-1; i+=2)
   {
        out.push_back(
            double_sha256(inp_list[i], inp_list[i+1])
        );
   }
   if (len % 2 == 1)
   {
        out.push_back(
            double_sha256(inp_list[len-1], inp_list[len-1])
        );
   }
   return calculate_merkle_root(out);
}



int main()
{
    std::ifstream infile("txids.txt");

    std::vector<std::vector<unsigned char> > txids;
    std::string line;
    int count = 0;
    while (std::getline(infile, line))
    {
        unsigned char* buf = OPENSSL_hexstr2buf(line.c_str(), nullptr);
        std::vector<unsigned char> buf2;
        for (int i=31; i>=0; i--)
        {
            buf2.push_back(
                buf[i]
            );
        }
        txids.push_back(
            buf2
        );
        count++;
    }
    infile.close();
    std::cout << count << std::endl;

    std::vector<std::vector<unsigned char> > merkle_root_hash;
    for (int k=0; k<1000; k++)
    {
        merkle_root_hash = calculate_merkle_root(txids);
    }
    std::vector<unsigned char> out0 = merkle_root_hash[0];
    std::vector<unsigned char> out;
    for (int i=31; i>=0; i--)
    {
        out.push_back(
            out0[i]
        );
    }

    static const char alpha[] = "0123456789abcdef";
    for (int i=0; i<32; i++)
    {
        unsigned char c = out[i];
        std::cout << alpha[ (c >> 4) & 0xF];
        std::cout << alpha[ c & 0xF];
    }
    std::cout.put('\n');

    return 0;
}

然而,与Python实现相比,性能较差(~4s):

$ g++ test.cpp -L/usr/local/opt/openssl/lib -I/usr/local/opt/openssl/include -lcrypto
$ time ./a.out 
1452
289792577c66cd75f5b1f961e50bd8ce6f36adfc4c087dc1584f573df49bd32e

real      0m9.245s
user      0m9.235s
sys       0m0.008s

完整的实现和输入文件可以在这里找到:test.cpp https://gist.github.com/andy121090/85a745f9886b791d4a980d00fb75ac27 and txids.txt https://gist.github.com/andy121090/93c08962f358df77190d0e6567d09531.

我怎样才能提高性能?默认情况下启用编译器优化吗?是否有比 sha256 更快的库openssl可用的?


您可以采取很多措施来优化代码。

以下是要点列表:

  • 编译器优化需要启用(使用-O3在海湾合作委员会);
  • std::array可以用来代替较慢的动态大小std::vector(因为哈希的大小是 32),甚至可以定义一个新的Hash为了清晰起见,请键入;
  • 参数应该通过引用传递(C++默认通过copy方式传递参数)
  • the C++ 向量可以被保留预先分配内存空间并避免不需要的副本;
  • OPENSSL_free必须被叫去释放分配的内存 of OPENSSL_hexstr2buf;
  • push_back当大小是编译时已知的常量时应避免;
  • using std::copy通常比手动复制更快(更干净);
  • std::reverse通常比手动循环更快(更干净);
  • 哈希的大小应该是 32,但是可以使用断言来检查以确保它没问题;
  • count不需要,因为它的大小txids vector;

这是生成的代码:

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <cstring>
#include <array>
#include <algorithm>
#include <cassert>

#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>

using Hash = std::array<unsigned char, 32>;

Hash double_sha256(const Hash& a, const Hash& b)
{
    assert(a.size() == 32 && b.size() == 32);

    unsigned char inp[64];
    std::copy(a.begin(), a.end(), inp);
    std::copy(b.begin(), b.end(), inp+32);

    const EVP_MD *md_algo = EVP_sha256();
    assert(EVP_MD_size(md_algo) == 32);

    unsigned int md_len = 32;
    Hash out;
    EVP_Digest(inp, 64, out.data(), &md_len, md_algo, nullptr);
    EVP_Digest(out.data(), md_len, out.data(), &md_len, md_algo, nullptr);
    return out;
}

std::vector<Hash> calculate_merkle_root(const std::vector<Hash>& inp_list)
{
   std::vector<Hash> out;
   int len = inp_list.size();
   out.reserve(len/2+2);
   if (len == 1)
   {
        out.push_back(inp_list[0]);
        return out;
   }
   for (int i=0; i<len-1; i+=2)
   {
        out.push_back(double_sha256(inp_list[i], inp_list[i+1]));
   }
   if (len % 2 == 1)
   {
        out.push_back(double_sha256(inp_list[len-1], inp_list[len-1]));
   }
   return calculate_merkle_root(out);
}

int main()
{
    std::ifstream infile("txids.txt");

    std::vector<Hash> txids;
    std::string line;
    while (std::getline(infile, line))
    {
        unsigned char* buf = OPENSSL_hexstr2buf(line.c_str(), nullptr);
        Hash buf2;
        std::copy(buf, buf+32, buf2.begin());
        std::reverse(buf2.begin(), buf2.end());
        txids.push_back(buf2);
        OPENSSL_free(buf);
    }
    infile.close();
    std::cout << txids.size() << std::endl;

    std::vector<Hash> merkle_root_hash;
    for (int k=0; k<1000; k++)
    {
        merkle_root_hash = calculate_merkle_root(txids);
    }
    Hash out0 = merkle_root_hash[0];
    Hash out = out0;
    std::reverse(out.begin(), out.end());

    static const char alpha[] = "0123456789abcdef";
    for (int i=0; i<32; i++)
    {
        unsigned char c = out[i];
        std::cout << alpha[ (c >> 4) & 0xF];
        std::cout << alpha[ c & 0xF];
    }
    std::cout.put('\n');

    return 0;
}

在我的机器上,这段代码比初始版本快 3 倍,比 Python 实现快 2 倍。

本次实施98%以上的时间花在EVP_Digest。因此,如果您想要更快的代码,您可以尝试找到一个更快的哈希库尽管 OpenSSL 应该已经相当快了。当前的代码已经成功地在主流 CPU 上每秒连续计算 170 万次哈希。这很好。或者,您也可以使用并行化程序OpenMP(这在我的 6 核机器上大约快 5 倍)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何提高C++中merkle根计算的速度? 的相关文章

  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 按成员序列化

    我已经实现了template
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况

随机推荐

  • C 中指向指针的问题

    我试图用 C 语言编写某种列表 而不为列表的头部创建全局变量 但我遇到了一些麻烦 我最初的代码是这样的 include
  • eclipse java代码显示行号

    我需要在 eclipse 上安装哪些插件才能使 java 文件显示行号 在 xml html 上显示行号怎么样 还有一种更简单的方法 只需右键单击装订线 代码所在的编辑器窗口的左边框 并启用它们 那里有一个特定的选项
  • 是否可以在 update_item 中结合 if_not_exists 和 list_append

    我正在尝试使用update itemboto3 中 DynamoDB 的功能 我现在正在努力更新项目列表 如果列表尚不存在 我想创建一个新列表 否则附加到现有列表 使用UpdateExpression形式的SET my list list
  • 限制列只接受 2 个值

    我的表中有一个名为 患者类型 的列 我想确保只有 2 个值可以插入到该列中 无论是 opd 还是 recognize 除此之外 所有其他输入都无效 下面是我想要的一个例子 如何确保该列仅接受 opd 或 admissed 作为 患者类型 列
  • MS Sql 服务器中的累计总数[重复]

    这个问题在这里已经有答案了 可能的重复 在 Sql Server 中计算运行总计 https stackoverflow com questions 860966 calculate a running total in sqlserver
  • 将 geom_boxplot 与 geom_line 结合起来

    我想使用组合箱线图和线图ggplot2 然而 我正在努力为每个组安排线路 g 连接 x 轴上类别的点 为了演示这个问题 df lt data frame x rep letters 1 3 each 5 y c 1 5 sample 10
  • 谷歌浏览器中的 ReportViewer 问题

    我在我的 asp net mvc C 应用程序中使用 Reportviewer 在 IE 和 Firefox 中 报表查看器看起来不错 但在 Chrome 中 标题和正文会缩小 我能够按照中的建议纠正标题显示问题http www mazso
  • 如何在不刷新的情况下更新页面

    在Gmail中 当收到新邮件时 页面会自动显示该邮件而不刷新 这是怎么做到的 您可以使用以下命令定期发送 AJAX 请求window setInterval http developer mozilla org en DOM window
  • 如何在 Symfony 2 / Doctrine 中启用 ENUM

    跑步时doctrine mapping import我收到错误 请求未知的数据库类型枚举 Doctrine DBAL Platforms MySqlPlatform 可能不支持它 看来我需要设置use native enum to true
  • TamperMonkey 中的 GM_addStyle 等效项

    是否有与 GreaseMonkey 相当的 TamperMonkeyGM addStyle添加CSS的方法 在 GreaseMonkey 中 您可以向多个元素添加一堆 CSS 属性 如下所示 GM addStyle body color w
  • Node.js 中确定一个路径是否是另一个路径的子目录

    我正在研究一个MQTT 处理程序 https github com jsdario replyer我想为每个有事件侦听器的父目录发出一个事件 例如 如果有以下可用的 MQTT 路径 其中有下标 这些路径有事件监听器 test replyer
  • 与大括号初始化末尾的额外“,”有任何关联吗?

    除了明显的名称之外 以下两个声明之间是否有区别 int main char str1 17 H e l l o char str2 17 H e l l o 第二个中多余的 是怎么回事 这有什么意义吗 两者似乎都编译得很好 在这种情况下 它
  • 我可以在 Django 中使用数据库视图作为模型吗?

    我想使用在数据库中创建的视图作为 django view 的源 不使用自定义sql 这可能吗 13 02 09 更新 就像许多答案所建议的那样 您可以在数据库中创建自己的视图 然后通过在 models py 中定义它来在 API 中使用它
  • 单字节异或密码 (python)

    这是我目前正在学习的现代密码学课程 挑战是 cryptopals 挑战 3 单字节 XOR 密码 我正在尝试使用 python 3 来帮助完成此任务 我知道我应该对字符串进行异或并转换为英语 十六进制字符串为 1b37373331363f7
  • ImageMagick - 与其他照片管理应用程序一样自动调整图像的颜色?

    一些照片管理应用程序 例如 flickr 网站上的 Picnic gnome 桌面上的 F Spot 可以选择 自动更正 自动修复 图像 这似乎可以调整图像中的颜色以使其看起来更美观好一些 例如 这是之前的 and after 无论如何 是
  • 联合中的字符串、段错误

    这基本上是一个标记联合 include
  • 我需要在 vba 中解释 activecell.offset

    我在理解一些 VBA 代码时遇到一些困难 我没有问题 activecell offset 1 1 select 但是 我有问题 activecell offset 1 1 range A1 select AND ActiveCell Off
  • TranslateAccelerator 和禁用的菜单项

    在我的应用程序中 我根据上下文启用 禁用菜单项 如果文本区域具有焦点 我会禁用与导航键冲突的加速器 例如 Ctrl 左 右 根据微软的文档 http msdn microsoft com en us library windows desk
  • 锚标记转到网页的错误部分

    这是问题所在的实际视频记录 我不想以任何方式做广告 https www youtube com watch v 7b38cQ0VGWI https www youtube com watch v 7b38cQ0VGWI 所以我创建一个网站只
  • 如何提高C++中merkle根计算的速度?

    我正在尝试尽可能优化默克尔根计算 到目前为止 我用 Python 实现了它 结果是这个问题 https stackoverflow com questions 67355203 how to improve the speed of mer