如此复杂的函数测试变量是否不为零有什么好处? 编辑

问题描述

我正在研究我的硕士学位论文(计算机科学),该论文是为后量子安全签名编写的。整个内容可以在here中找到,但在这里并不重要。在我的论文中,我试图解释一个“简单”的功能,但它并不是那么简单。

函数测试 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
}

我了解了它的工作原理,但是我不明白为什么这个功能需要 this 复杂。可能有充分的理由吗?充分的理由可能是性能或安全性(例如,针对定时攻击的安全性)收益。因为如果没有这样的好处,那么以一种简单的方式编写该函数会不会更聪明:

static inline uint8_t gf16_is_nonzero(uint8_t a) {
    return (a & 15) != 0;
}

编辑

代码不是我写的,它是由加密研究编写的,他们正试图通过NIST将其PQ算法标准化。

TonyDelroy在评论中建议了一种更简单的方法来处理第二个代码段。

解决方法

使用此代码的原因是因为它无分支

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

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

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

第二个函数编译为此:

andl    $15,%edi
setne   %al
ret

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