4

我正在写关于为后量子安全签名编写的代码的硕士论文(计算机科学)。整个事情都可以在这里找到,但在这里并不重要。对于我的论文,我试图解释一个“简单”的功能,这根本不是那么简单。

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 在评论中建议了第二个代码片段的更简单方法。

4

1 回答 1

8

这段代码的原因是因为它是无分支的。

测试条件往往是一项昂贵的操作,而加法、减法和按位运算符则不然。

然而,这是过早的优化。使用-O3,第一个函数编译为:

andl    $15, %edi
negl    %edi
shrl    $31, %edi
movl    %edi, %eax
ret

而第二个函数编译为:

andl    $15, %edi
setne   %al
ret

故事的寓意:编写清楚地说明您的意图的代码,让编译器找出其余的。

于 2020-08-25T20:59:53.067 回答