【问题标题】:Reducing an integer to 1 if it is not equal to 0如果不等于 0,则将整数减为 1
【发布时间】:2017-08-10 18:19:29
【问题描述】:

我试图通过删除代码中的 if 语句来解决时序泄漏,但由于 c++ 对 if 语句中整数输入的解释,我被卡住了。

请注意,我假设编译器确实创建了一个条件分支,这会导致时序信息泄露!

原代码为:

int s
if (s)
   r = A
else
   r = B

现在我正在尝试将其重写为:

int s;
r = sA+(1-s)B

因为 s 未绑定到 [0,1],所以如果 s 不在 [0,1] 范围内,我会遇到这样的问题:它会错误地乘以 A 和 B。如果不使用 s 上的 if 语句来解决这个问题,我该怎么办?

提前致谢

【问题讨论】:

  • 使用!!s进行规范化?
  • 在某些编译器/架构组合中,r= s ? A : B; 将被转换为无分支代码(使用条件赋值)。
  • 在@nwp、!!s * A + !s * B 或更好的A + !s * (B - A) 之后。
  • 这不就是说:s = not not not s吗?如果有,为什么会有帮助?它解决了我的错误。
  • @David 我也没有,但我听说过timing attack(也在标签中),而定时泄漏似乎正是定时攻击成功的原因。

标签: c++ c if-statement timing-attack


【解决方案1】:

你有什么证据表明 if 语句导致了时序泄漏?

如果您使用启用了优化的现代编译器,则该代码不应生成分支。您应该通过查看汇编语言输出来检查您的编译器在做什么。

例如,g++ 5.3.0 编译这段代码:

int f(int s, int A, int B) {
  int r;
  if (s)
    r = A;
  else
    r = B;

  return r;
}

到这个大会:

movl    %esi, %eax
testl   %edi, %edi
cmove   %edx, %eax
ret

看,妈!没有树枝! ;)

【讨论】:

  • 这个任务是学校练习的一部分,我们不得不假设编译器没有进行智能优化并且实际上分支,导致秘密变量 s 的时间泄漏。
  • @Kasper 那么你的问题是无法回答的,因为它没有定义什么分支和不分支。例如,建议的!!s 在功能上等同于s ? 1 : 0,并且根据所讨论的编译器,也可以分支。它与微软的编译器有关。
  • 即使它们是等价的,s ? 1 : 0 也不会泄漏 s 的计时信息,这与我的问题中的代码不同。我本来可以更清楚地知道什么是分支,什么不是,但我的问题是更简洁的:如果整数不等于 0,如何将其减少为 1?这当然是可以回答的。
  • @Kasper 在真实的 CPU 上,当s ? 1 : 0 分支时,它确实 泄漏时间信息,因为分支预测使一个分支比另一个更快。如果整数 1 不为零,则其答案通常只是if (x) x = 1;,但这对您来说并不是一个有用的具体时间答案。
【解决方案2】:

如果您知道整数中的位数,那就很容易了,尽管有一些复杂性使它成为标准的干净并且可能出现不寻常的整数表示。

这是 32 位整数的一种简单解决方案:

uint32_t mask = s;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
mask &= 1;
r = b ^ (-mask & (a ^ b)):

五个移位和或语句传播mask中的任何设置位,因此最终低位为1,除非掩码最初为0。然后我们隔离低位,导致1 或 0。最后一条语句相当于您的两个乘法和加法。

这是一个更快的方法,基于以下观察:如果你从一个数字中减去一个并且符号位从 0 变为 1,那么这个数字就是 0:

uint32_t mask = ((uint32_t(s)-1U)&~uint32_t(s))>>31) - 1U;

这与减去 1 然后使用进位位的计算基本相同,但不幸的是,进位位不会暴露给 C 语言(可能通过编译器特定的内在函数除外)。

其他变体也是可能的。

【讨论】:

    【解决方案3】:

    当优化不可用时,没有分支的唯一方法是使用内联汇编。假设 8086:

    mov ax, s
    neg ax        ; CF = (ax != 0)
    sbb ax, ax    ; ax = (s != 0 ? -1 : 0)
    neg ax        ; ax = (s != 0 ? 1 : 0)
    mov s, ax     ; now use s at will, it will be: s = (s != 0 ? 1 : 0)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-21
      • 2017-01-23
      • 1970-01-01
      • 1970-01-01
      • 2013-08-17
      • 2021-05-03
      相关资源
      最近更新 更多