C 如何编写一个恒定时间函数,将最高有效位复制到所有位

C 如何编写一个恒定时间函数,将最高有效位复制到所有位,c,cryptography,bit-manipulation,C,Cryptography,Bit Manipulation,我想用C编写一个函数,它取uint8\u t的MSB,如果设置了它,则返回0xFF,如果没有0x00。简而言之,它返回一个整数,其中所有位都设置为与MSB相同的值 但我想用一种完全恒定的时间方式来做,没有分支,没有数组偏移,只有数学运算,保证总是接触相同数量的位。理想情况下,没有任何未定义的行为。如何做到这一点?如何: #define uint8_msb_to_all_bits(x) (0xFF * ((x) >> 7)) 或者更好: #define uint8_msb_to_al

我想用C编写一个函数,它取
uint8\u t
的MSB,如果设置了它,则返回
0xFF
,如果没有
0x00
。简而言之,它返回一个整数,其中所有位都设置为与MSB相同的值

但我想用一种完全恒定的时间方式来做,没有分支,没有数组偏移,只有数学运算,保证总是接触相同数量的位。理想情况下,没有任何未定义的行为。如何做到这一点?

如何:

#define uint8_msb_to_all_bits(x) (0xFF * ((x) >> 7))
或者更好:

#define uint8_msb_to_all_bits(x) (-((x) >> 7))
这两种方法的工作原理是,如果
x
是一个8位无符号整数,那么
x>>7
如果
x
的MSB设置为1,否则为0。剩下的就是将1映射到0xFF,这可以通过乘法实现,或者在这种特殊情况下,只需对数字求反即可


(是的。)

鉴于您的
uint8\u t
声明:

uint8_t x = // MSB is either 1 or 0 if `x` depending on the signed value of `x`
假定有符号整数为2的补码的欺骗:

return (((uint16_t)(int8_t)x) >> 8) & 0xff;
那怎么办

- (x >> 7)
?


只有MSB被保留,数学求反被用来将其复制到所有位。

在现代CPU上求无符号的反需要恒定的时间吗?@AlexGaynor:如果没有,我会非常惊讶;它可能编译成一条恒定时间汇编指令。仅仅因为某个指令是一条指令,并不意味着所有输入所用的时间都相同(例如,IDIV是可变时间,任何涉及内存的东西都是可变时间)。在x86平台上,它可能编译成
neg
sub
(除非聪明的编译器将其优化为
sar
),否则两者的执行时间都不应取决于输入。但是,当然,人们永远无法事先真正知道某个疯狂的编译器(或CPU设计器!)可能会这样做,因此确保的唯一方法是首先检查程序集,然后对其进行基准测试。请注意,第二个选项将返回
-1
,类型为
int
——如果希望使用
0xFF
,最好将结果显式转换为
uint8\u t
。在使用2的补码算法的系统上,您可能会bly不需要
(uint16\u t)
强制转换,因为只要将有符号的值右移就可以编译为。当然,从技术上讲,这一切(从
(int8\u t)
强制转换开始)是实现定义的行为,因此无法保证任何东西。@IlmariKaronen确切地说……强制转换只是为了安全。但是,感谢您指出这一点。@JensGustedt为什么应该是6,确切地说?@H2CO3-一个问题-您为什么要添加
&0xff
?强制转换到
(int8\t)x
允许
x
以后通过
(uint16\u t)
符号扩展到16位。现在
(uint16\u t)(int8\t)x
只是16位的值,它将
x的位7复制到位8..15。无符号值的右移将0放入msb,所以在
>8
位8..15之后,无论
x的位是多少,它都将是0。@Artur只是为了安全。安全总比抱歉好。在C中,我使用了与
(uint8u t)((int8u)7)等价的值
,但我不确定这在C中是否定义得很好。@CodesInChaos:不是;右移位有符号值的结果是实现定义的,尽管在实践中,很难找到一个没有将其编译为算术移位的实现。(基本上,C标准没有定义它的原因是因为它没有假设有符号算术必须使用2的补码来完成。)