環境
OpenSSLの機能 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 操作に一定の時間がかかるようにするために、この関数は 2 つの bignum を交換するか、一定の時間内にそのままにしておくことが意図されています。それらをそのままにしておくと、実際に各 bignum の各単語を読み取り、古い単語と同一の新しい単語を計算し、その結果を元の場所に書き戻します。
これには、bignum が効果的に交換された場合と同じ時間がかかることが意図されています。
この質問では、Agner Fog が最適化マニュアルで説明しているような最新の広範なアーキテクチャを想定しています。C コードからアセンブリへの直接的な変換 (C コンパイラーがプログラマーの努力を台無しにすることなく) も想定されています。
質問
上記の構成が「ベスト エフォート」型の一定時間実行として特徴付けられるのか、それとも完全な一定時間実行として特徴付けられるのかを理解しようとしています。
a
特に、関数が呼び出されたときに bignum がすでに L1 データ キャッシュにあり、BN_consttime_swap
関数が返された直後のコードがすぐに bignum で作業を開始するというシナリオが懸念されa
ます。最新のプロセッサでは、bignuma
が使用されたときにコピーが技術的に終了しないように、同時に十分な数の命令を実行できます。BN_consttime_swap
への呼び出しの後の命令が動作するようにするメカニズムa
は、メモリ依存スペキュレーションです。議論のために単純なメモリ依存の推測を仮定しましょう。
質問が要約すると、これは次のとおりです。
BN_consttime_swap
メモリから読み取られた後、投機に反して関数内に書き込まれたコードをプロセッサが最終的に検出した場合、プロセッサはアドレスが書き込まれたことを検出するとすぐに投機的実行をキャンセルしますか、それともそれ自体を許可しますか?書き込まれた値が既に存在していた値と同じであることを検出したときにそれを保持するには?
最初のケースでは、BN_consttime_swap
完全な定数時間を実装しているように見えます。2 番目のケースでは、ベストエフォートの定数時間のみです。bignum がスワップされていない場合、への呼び出しの後に来るコードの実行は、スワップBN_consttime_swap
されている場合よりもかなり高速になります。
2 番目のケースでも、これは、2 つの bignum のそれぞれの単語ごとに、2 つの可能な final とは異なる値を書き込むことによって、近い将来 (プロセッサが十分に素朴である限り) 修正できるように見えるものです。古い値または新しい値を再度書き込む前に値を変更します。通常のvolatile
コンパイラがシーケンスを過度に最適化するのを防ぐために、ある時点で型修飾子を含める必要があるかもしれませんが、それでも可能に思えます。
注:ストア転送については知っていますが、ストア転送はショートカットにすぎません。後に来るはずの書き込みの前に読み取りが実行されることを防ぎません。そして、状況によっては失敗しますが、この場合は期待できません。