1

我试图通过删除代码中的 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 语句来解决这个问题,我该怎么办?

提前致谢

4

3 回答 3

1

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

这是 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 语言(可能通过编译器特定的内在函数除外)。

其他变化是可能的。

于 2017-03-19T14:52:51.850 回答
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

看,妈!没有树枝!;)

于 2017-03-19T13:55:15.287 回答
-1

当优化不可用时,没有分支的唯一方法是诉诸内联汇编。假设 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)
于 2017-03-19T14:26:53.923 回答