OpenSSL中的function BN_consttime_swap
非常美观。在此代码段中,condition
已计算为0
或(BN_ULONG)-1
:
#define BN_CONSTTIME_SWAP(ind) \
do { \
t = (a->d[ind] ^ b->d[ind]) & condition; \
a->d[ind] ^= t; \
b->d[ind] ^= t; \
} while (0)
…
BN_CONSTTIME_SWAP(9);
…
BN_CONSTTIME_SWAP(8);
…
BN_CONSTTIME_SWAP(7);
目的是为了确保更高级别的bignum操作占用恒定时间,此功能可以交换两个bignum或在恒定时间内将它们保留在原位。当它离开它们时,它实际上读取每个bignum的每个单词,计算一个与旧单词相同的新单词,并将该结果写回原始位置。
目的是这将花费相同的时间,好像有效地交换了bignums。
在这个问题中,我假设一个现代的,广泛的架构,例如Agner Fog在他的optimization manuals中所描述的架构。还假设C代码直接转换为汇编(没有C编译器撤消程序员的努力)。
我试图了解上面的构造是否表征为“尽力而为”的恒定时间执行,或者是完美的恒定时间执行。
特别是,我担心在调用函数a
时bignum BN_consttime_swap
已经在L1数据缓存中的情况,并且函数返回后的代码开始在bignum上工作a
马上。在现代处理器上,当使用bignum a
时,足够的指令可以同时在飞行中,以使副本在技术上不完整。在调用BN_consttime_swap
后允许指令在a
上工作的机制是内存依赖性推测。让我们假设naive memory dependence speculation为了论证。
问题似乎归结为:
当处理器最终检测到BN_consttime_swap
之后的代码从内存中读取时,与推测相反,该代码已写入函数内部,一旦检测到该代码,它就会取消推测执行地址已被写入,或者它是否允许自己在检测到已写入的值与已存在的值相同时保留它?
在第一种情况下,BN_consttime_swap
看起来像是实现了完美的恒定时间。在第二种情况下,它只是尽力而为的常量时间:如果没有交换bignums,那么在调用BN_consttime_swap
之后执行的代码将比它们被交换时快得多。
即使在第二种情况下,这看起来似乎可以在可预见的将来修复(只要处理器保持天真),对于两个bignums中的每一个的每个单词,写一个不同于在再次写入旧值或新值之前的两个可能的最终值。可能需要在某些时候涉及volatile
类型限定符以防止普通编译器过度优化序列,但听起来仍然可能。
注意:我知道 store forwarding ,但商店转发只是一种捷径。它不会阻止在>之前>>执行读取之前执行的读取。在某些情况下,它会失败,尽管在这种情况下人们不会指望它。
答案 0 :(得分:17)
还假设C代码直接转换为汇编(没有C编译器撤消程序员的努力)。
我知道这不是你问题的主旨,我知道你知道这一点,但我需要咆哮一分钟。这甚至没有资格作为提供恒定时间执行的“尽力而为”尝试。许可编译器检查condition
的值,如果condition
为零,则跳过整个事件。模糊condition
的设置会降低这种可能性,但不能保证。
据称“常量时间”代码不应该用C语言写成,完全停止。即使它是今天的恒定时间,在您测试的编译器上,一个更聪明的编译器也会出现并击败您。您的其中一个用户将在使用此编译器之前使用此编译器,并且他们不会意识到您将其暴露给它们的风险。我知道有三种实现恒定时间的方法:专用硬件,汇编或生成机器代码的DSL以及恒定时间执行的证明。
抛开一边,看看手头上的实际架构问题:假设一个愚蠢的天真的编译器,这段代码是我熟悉的μ问题上的常量时间来评估这个问题,我希望它对于一个人来说是广泛的。原因很简单:力量。我希望检查存储队列或缓存,如果存储的值与已存在的值匹配并有条件地使存储短路或避免弄脏每个商店的缓存行消耗的能量比在极少数情况下节省的能量消耗更多避免一些工作。但是,我不是CPU设计师,并且不会假设代表他们发言,所以请用几汤匙盐,并在假设这是真的之前咨询一个。
答案 1 :(得分:1)
持续时间实现背后的想法并不是要在恒定时间内实际执行所有操作。这种情况永远不会发生在无序架构上。 要求是时间分析不能揭示任何秘密信息。 为了防止这种情况,基本上有两个要求:
a)不要使用任何秘密作为循环的停止条件,或作为分支的谓词。如果不这样做,您将进入分支预测攻击https://eprint.iacr.org/2006/351.pdf
b)不要使用任何秘密作为内存访问的索引。这会导致缓存时序攻击http://www.daemonology.net/papers/htt.pdf
至于你的代码:假设你的秘密是"条件"并且可能是a和b的内容,代码是完全恒定的时间,因为它的执行不依赖于a,b和条件的实际内容。当然,内存中a和b的位置会影响循环的执行时间,但不会影响秘密的内容。 这是假设当然条件是以恒定时间方式计算的。 至于C优化:编译器只能根据它知道的信息优化代码。如果"条件"真正的秘密是编译器不应该能够辨别它的内容并进行优化。如果可以从您的代码中扣除,那么编译器很可能会对0情况进行优化。