接近恒定时间旋转,不违反标准

2023-11-29

我花了很长时间试图想出一个不违反 C/C++ 标准的恒定时间旋转。

问题是边缘/角落情况,其中操作在算法中调用并且这些算法无法更改。例如,以下内容来自Crypto++并执行下面的测试工具海湾合作委员会乌桑 (i.e., g++ fsanitize=undefined):

$ ./cryptest.exe v | grep runtime
misc.h:637:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:643:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:625:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:637:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:643:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:637:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'

代码位于misc.h:637:

template <class T> inline T rotlMod(T x, unsigned int y)
{
    y %= sizeof(T)*8;
    return T((x<<y) | (x>>(sizeof(T)*8-y)));
}

Intel的ICC特别无情,把整个函数调用都去掉了,连y %= sizeof(T)*8。几年前我们修复了这个问题,但由于缺乏恒定的时间解决方案,所以保留了其他勘误表。

还剩下一个痛点。什么时候y = 0,我得到一个条件32 - y = 32,并设置未定义的行为。If我添加了一个检查if(y == 0) ...,那么该代码无法满足恒定时间要求。

我研究了许多其他实现,从 Linux 内核到其他加密库。它们都包含相同的未定义行为,因此这似乎是一个死胡同。

如何使用最少的指令在几乎恒定的时间内执行旋转?

EDIT: by 接近恒定时间,我的意思是避免分支,以便始终执行相同的指令。我不担心 CPU 微码计时。虽然分支预测在 x86/x64 上可能很棒,但在其他平台(例如嵌入式平台)上可能表现不佳。


如果以下情况,则不需要这些技巧:GCC or Clang提供了一个内在的执行以接近恒定的时间旋转。我什至会选择“执行轮换”,因为他们甚至没有。


我已链接到此答案,以获取其他几个“旋转”问题的完整详细信息,包括这个社区维基问题,应与最佳实践保持同步。

我找到了一篇关于这个问题的博客文章,看起来它终于解决了问题(使用足够新的编译器版本)。

约翰·雷格尔,犹他大学推荐他尝试制作旋转函数的版本“c”。我用按位 AND 替换了他的断言,发现它仍然编译为单个旋转 insn。

typedef uint32_t rotwidth_t;  // parameterize for comparing compiler output with various sizes

rotwidth_t rotl (rotwidth_t x, unsigned int n)
{
  const unsigned int mask = (CHAR_BIT*sizeof(x)-1);  // e.g. 31

  assert ( (n<=mask)  &&"rotate by type width or more");
  n &= mask;  // avoid undef behaviour with NDEBUG.  0 overhead for most types / compilers
  return (x<<n) | (x>>( (-n)&mask ));
}

rotwidth_t rot_const(rotwidth_t x)
{
  return rotl(x, 7);
}

这可以在 x 的类型上进行模板化,但对于实际使用来说可能更有意义,在函数名称中包含宽度(例如rotl32)。通常,当您旋转时,您知道想要的宽度,这比当前存储值的大小变量更重要。

还要确保仅将其与无符号类型一起使用。有符号类型的右移会进行算术移位,即符号位的移位。 (从技术上讲,这是依赖于实现的行为,但现在一切都使用 2 的补码。)

Pabigot 在我之前独立提出了同样的想法,并发布到github上。他的版本具有 C++ static_assert 检查,以使其在使用类型范围之外的循环计数时出现编译时错误。

I 使用 gcc.godbolt.org 测试了我的,定义了 NDEBUG,对于变量和编译时常量循环计数:

  • gcc:最佳代码海湾合作委员会 >= 4.9.0,非分支 neg+shift+or 与较早的。
    (编译时 const 计数:gcc 4.4.7 就可以了)
  • clang:最佳代码铿锵> = 3.5.0,非分支 neg+shift+or 与较早的。
    (编译时 const 循环计数:clang 3.0 就可以了)
  • icc 13:最佳代码。
    (使用 -march=native 进行编译时 const 计数:生成速度较慢shld $7, %edi, %edi。没有就好-march=native)

即使较新的编译器版本也可以处理维基百科中常见的代码(包含在 godbolt 示例中),而无需生成分支或 cmov。 John Regehr 的版本具有避免循环计数为 0 时出现未定义行为的优点。

8 位和 16 位循环有一些注意事项,但编译器似乎可以使用 32 位或 64 位,当n is uint32_t。参见代码中的注释神螺栓链接一些我测试各种宽度的笔记uint*_t。希望所有编译器都能更好地识别这个习惯用法,以便将来有更多类型宽度的组合。有时 gcc 会无用地发出AND旋转计数上的 insn,即使 x86 ISA 定义了以精确 AND 作为第一步的旋转 insn。

“最佳”意味着效率为:

# gcc 4.9.2 rotl(unsigned int, unsigned int):
    movl    %edi, %eax
    movl    %esi, %ecx
    roll    %cl, %eax
    ret
# rot_const(unsigned int):
    movl    %edi, %eax
    roll    $7, %eax
    ret

内联时,编译器应该能够首先将值安排在正确的寄存器中,从而仅进行一次循环。

使用较旧的编译器,当循环计数是编译时常量时,您仍然可以获得理想的代码。 Godbolt 允许您以 ARM 作为目标进行测试,并且它也在那里使用了旋转。在较旧的编译器上使用变量计数时,您会得到一些代码膨胀,但不会出现分支或主要性能问题,因此通常可以安全地使用该习惯用法。

顺便说一句,我修改了 John Regehr 的原始版本以使用 CHAR_BIT*sizeof(x),并且 gcc / clang / icc 发出最佳代码uint64_t以及。然而,我确实注意到改变x to uint64_t而函数返回类型仍然是uint32_t让 gcc 将其编译为移位/或。因此,如果您想要 64b 旋转的低 32b,请小心将结果转换为单独序列点中的 32 位。即,将结果分配给 64 位变量,然后转换/返回它。 icc 仍会生成旋转 insn,但 gcc 和 clang 不会生成,因为

// generates slow code: cast separately.
uint32_t r = (uint32_t)( (x<<n) | (x>>( -n&(CHAR_BIT*sizeof(x)-1) )) );

如果任何人都可以使用 MSVC 对此进行测试,那么了解那里发生的情况将会很有用。

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

接近恒定时间旋转,不违反标准 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags

随机推荐

  • 将 UDP 输入传送到 FFMPEG

    摄像机正在本地端口上通过 UDP 以 RTP 形式向我发送视频数据 ffmpeg 是否支持将输入 H 264 有效负载 自动转换为 MP4 怎么做 这应该有效 ffmpeg i udp localhost 1234 vcodec copy
  • 如何在Python中有效地检查给定的IP地址是否属于IP子网?

    我有一组大约 200 000 个 IP 地址和 10 000 个 1 1 1 1 24 形式的子网 对于每个 IP 地址 我需要检查它是否属于这些子网之一 但由于它是一个如此大的数据集 而且我的计算能力较低 我希望对此有一个有效的实现 在搜
  • mysql存储过程从表中设置值

    我有一个简单的表如下 mysql gt select from version id version 1 1 1 row in set 0 00 sec 我需要创建一个存储过程 它将根据该表的值 准确地说 该表的唯一行 执行某些操作 或不执
  • Excel 宏通过 powershell 运行,但在 Windows 任务计划程序运行时不运行

    我有一个脚本检查 Excel 文件的文件夹 然后如果此 阈值 大于 0 则运行另一个 Excel 文件中的宏来与这些 Excel 文件夹交互 当我通过 powershell ISE 手动运行该进程时 它工作正常 但是当我使用 Windows
  • 确定绑定到事件的事件处理程序列表

    我有一个无法关闭的 WinForms 表单 在 OnFormClosing 中 e Cancel 设置为 true 我猜测我的应用程序中的某些对象已绑定到 Closing 或 FormClosing 事件 并且正在阻止关闭 为了找到答案 我
  • 有没有办法在 linq 查询中参数化方法?

    在我使用 Linq to SQL 的应用程序中 用户可以搜索文本 可以在搜索表达式的开头和 或结尾使用星号 现在的代码是这样的 var search SearchTextBox Text Trim bool filterStartsWith
  • 读取串行输入并打印到 Tkinter GUI

    我正在尝试制作一个基于 Tkinter 的 GUI 用于 Arduino 打印传感器值并响应用户输入 我试图用来消除 while 循环的代码是这样的 它不打印任何传感器信息 唯一的输出是 正在尝试 dev ttyACM0 然后打开 tkin
  • 获取 .bat 文件中的图像文件尺寸

    我有一个bat文件 列出了文件夹中所有图像的路径 代码是 echo off break gt infofile txt for f delims F in dir b s bmp do echo F 1 1 1 100 100 gt gt
  • 如何在 nginx 中包含位置块?

    我在用着nginx作为 2 个网络应用程序的反向代理 这两个网络应用程序 UI 共享位置代理 因为后端服务是共享的 如何组合位置块并将它们包含在服务器中 主机配置文件 server server name app1 com listen 8
  • 加密加密属性文件中的密码

    Problem 我正在使用 Apache CXF 3 0 7 并在新功能您可以在加密属性文件中存储密钥库密码的 BASE 64 编码 加密版本 但我不知道如何添加它 我没有找到此实现的示例 在 apache web 中说 加密属性文件内容的
  • 为什么 NULL = NULL 在 SQL Server 中计算结果为 false

    在 SQL Server 中 如果你有nullParam NULL在 where 子句中 它的计算结果始终为 false 这是违反直觉的 给我带来了很多错误 我确实明白IS NULL and IS NOT NULL关键字是正确的方法 但为什
  • 如何解决 Multer 错误:意外的表单结束?

    我发现了有关 Multer 的其他类似问题 但没有答案 我正在尝试使用 next js 前端 和 node js 后端 上传文件 使用开发工具时 数据是通过网络选项卡发布的 以下是我的设置 app js const express requ
  • iOS 6.0 MPMoviePlayerController 全屏模式黑色?然后应用程序不再阻止任何操作

    当屏幕为黑色时 MPMoviePlayerController 视频将进入全屏模式 然后该应用程序就被屏蔽了 此问题仅适用于 iOS 6 0 但 iOS 5 1 运行良好 这是我的代码 如果我双击播放器全屏打开 但显示黑屏 self mov
  • PHP 数组语法:array(...) 或 [...] [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 在 PHP 中 这些相同吗 x 1 2 3 and x array 1 2 3 这两种创建数组的方法是否存在不同的情况 有什么理由使用其中一种而不是另一种吗 它们与警告相同 x 1 2 3
  • 在 Access 中从另一个表的数据创建一个表

    这个问题是关于 MS Access 的 我想做的是 我在 Access 中有一个表 并且想使用第一个表中的数据创建另一个表 希望通过一些 VBA 代码自动创建 有关于如何执行此操作的任何建议吗 我对 VBA 和 Access 很陌生 因此任
  • Web API:具有不同 HTTP 动词的相同方法

    在 WEB API 控制器中 我们可以使用相同的方法名称和不同的 HTTP 动词吗 HttpGet public string Test return Success Get HttpPost public string Test int
  • 正则表达式多个条件

    我有一个包含 URL 的字符串 例如https xxxx yyyy com en 我怎样才能制作一个正则表达式来验证这一点both这些条件都满足吗 网址不包含xxxx The URL does包含任一 en or en 您可以使用 xxxx
  • 重定向选择框中的选择选项

    目前我正在使用这个
  • 合并具有大写和非大写版本的变量名称的列,而不指定变量名称

    我有一个 大 数据框 如下所示 library data table DT lt fread ID country year A b B a 4 NLD 2002 NA 1 NA 0 5 NLD 2002 NA 0 NA 1 6 NLD 2
  • 接近恒定时间旋转,不违反标准

    我花了很长时间试图想出一个不违反 C C 标准的恒定时间旋转 问题是边缘 角落情况 其中操作在算法中调用并且这些算法无法更改 例如 以下内容来自Crypto 并执行下面的测试工具海湾合作委员会乌桑 i e g fsanitize undef