如此复杂的函数来测试变量是否不为零可能有什么好处?
What could be the benefit of such a complicated function to test if variable is not zero?
我正在写我的硕士论文(计算机科学),内容是为 post-quantum-secure 签名编写的代码。整个事情都可以找到 here 但在这里并不重要。对于我的论文,我试图解释一个 'simple' 函数,它根本不是那么简单。
函数测试 galois-field GF(16) 中的变量是否非零。 (这里的GF(16)可以理解为4位无符号整数)。该函数如下所示:
static inline uint8_t gf16_is_nonzero(uint8_t a) {
unsigned a4 = a & 0xf; // mask lowest 4 bits of a
unsigned r = 0u - a4; // set 4 high bits if a is nonzero
r >>= 4; // right-shift high bits into low bits
return r & 1; // return lowest bit
}
我明白它是如何工作的,但我不明白为什么这个函数需要这个复杂。这有充分的理由吗?充分的理由可能是性能或安全性(例如针对定时攻击的安全性)的好处。因为如果没有这样的好处,那么以一种简单的方式编写该函数不是更聪明吗:
static inline uint8_t gf16_is_nonzero(uint8_t a) {
return (a & 15) != 0;
}
编辑
这段代码不是我写的,它是由密码研究人员编写的,他们正试图让他们的 PQ 算法被 NIST 标准化。
TonyDelroy 在评论中建议了第二个代码片段的更简单方法。
此代码的原因是因为它无分支。
条件测试往往是一项昂贵的操作,而加法、减法和按位运算符则不然。
然而,这是过早的优化。使用 -O3
,第一个函数编译为:
andl , %edi
negl %edi
shrl , %edi
movl %edi, %eax
ret
虽然第二个函数编译成这样:
andl , %edi
setne %al
ret
故事的寓意:编写清楚说明您的意图的代码,让编译器找出其余部分。
我正在写我的硕士论文(计算机科学),内容是为 post-quantum-secure 签名编写的代码。整个事情都可以找到 here 但在这里并不重要。对于我的论文,我试图解释一个 'simple' 函数,它根本不是那么简单。
函数测试 galois-field GF(16) 中的变量是否非零。 (这里的GF(16)可以理解为4位无符号整数)。该函数如下所示:
static inline uint8_t gf16_is_nonzero(uint8_t a) {
unsigned a4 = a & 0xf; // mask lowest 4 bits of a
unsigned r = 0u - a4; // set 4 high bits if a is nonzero
r >>= 4; // right-shift high bits into low bits
return r & 1; // return lowest bit
}
我明白它是如何工作的,但我不明白为什么这个函数需要这个复杂。这有充分的理由吗?充分的理由可能是性能或安全性(例如针对定时攻击的安全性)的好处。因为如果没有这样的好处,那么以一种简单的方式编写该函数不是更聪明吗:
static inline uint8_t gf16_is_nonzero(uint8_t a) {
return (a & 15) != 0;
}
编辑
这段代码不是我写的,它是由密码研究人员编写的,他们正试图让他们的 PQ 算法被 NIST 标准化。
TonyDelroy 在评论中建议了第二个代码片段的更简单方法。
此代码的原因是因为它无分支。
条件测试往往是一项昂贵的操作,而加法、减法和按位运算符则不然。
然而,这是过早的优化。使用 -O3
,第一个函数编译为:
andl , %edi
negl %edi
shrl , %edi
movl %edi, %eax
ret
虽然第二个函数编译成这样:
andl , %edi
setne %al
ret
故事的寓意:编写清楚说明您的意图的代码,让编译器找出其余部分。