私は、C/C++ 標準に違反しない一定時間のローテーションを考え出すのにかなりの時間を費やしています。
問題は、操作がアルゴリズムで呼び出され、それらのアルゴリズムを変更できないエッジ/コーナー ケースです。たとえば、次はCrypto++からのもので、 GCC ubsan (つまりg++ fsanitize=undefined
)でテスト ハーネスを実行します。
$ ./cryptest.exe v | grep runtime
misc.h:637:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:643:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:625:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:637:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:643:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
misc.h:637:22: runtime error: shift exponent 32 is too large for 32-bit type 'unsigned int'
そしてのコードmisc.h:637
:
template <class T> inline T rotlMod(T x, unsigned int y)
{
y %= sizeof(T)*8;
return T((x<<y) | (x>>(sizeof(T)*8-y)));
}
Intel の ICC は特に冷酷で、関数呼び出し全体を削除し、y %= sizeof(T)*8
. 数年前に修正しましたが、一定時間の解決策がないため、他のエラータはそのまま残しました。
残りの 1 つの問題点があります。の場合y = 0
、条件 where を取得32 - y = 32
し、未定義の動作を設定します。のチェックを追加するとif(y == 0) ...
、コードは一定時間の要件を満たせなくなります。
Linux カーネルから他の暗号化ライブラリまで、他の多くの実装を見てきました。それらはすべて同じ未定義の動作を含んでいるため、行き止まりのように見えます。
最小数の命令でほぼ一定の時間で回転を実行するにはどうすればよいですか?
編集:ほぼ一定の時間までに、分岐を回避することを意味するため、同じ命令が常に実行されます。CPU マイクロコードのタイミングについては心配していません。分岐予測は x86/x64 では優れているかもしれませんが、組み込みなどの他のプラットフォームではうまく機能しない可能性があります。
GCCまたはClangがほぼ一定の時間で回転を実行する組み込み関数を提供する場合、これらのトリックは必要ありません。彼らにはそれさえないので、私は「回転を実行する」ことさえ解決します。