Symmetric

Salsa20 中“xor-a-rotated-sum”而不是“add-a-rotated-xor”背後的性能原因是什麼?

  • October 20, 2022

我目前正在閱讀 Salsa20 的規範(連結)。關於他是否選擇“xor-a-rotated-sum”而不是“add-a-rotated-xor”的 DJB 聲明如下:

除了 xor-a-rotated-sum 之外,是否還有其他修改? 有許多合理的方法可以使用同一列中的其他單詞來修改列中的每個單詞。我選擇“異或旋轉和”作為在關鍵路徑上的不兼容結構之間來回彈跳。出於簡單的性能原因,我選擇“xor a rotate sum”而不是“add a rotate xor”:x86 架構具有三操作數加法 (LEA),但沒有三操作數 xor。

首先,我不明白為什麼要提到三操作數操作,因為每個操作無論是異或還是加法都是針對一對單詞完成的。另外,起初,根據我對嵌入式系統的一點了解和我所做的一些研究,可以使用LEA提到的指令完成很多“棘手的黑客攻擊”,例如123。但是如上一個參考文獻中所見,三個操作數的加法不能在一條 x86 指令中完成,儘管如第二個參考文獻中所述,它們可以並行化。但是,我仍然懷疑 3 個參數相加會比三個參數 xor 更快。

所以問題是,為什麼我們會為 3 個參數運算而煩惱,是否有證據表明 3 個參數相加比 3 個參數 xor 更快?

三操作數表示兩個源寄存器和一個目標寄存器。大多數 x86 指令將源寄存器之一重用為目標,因此如果需要保存它,則必須使用額外的 MOV 指令來複製源寄存器之一。其他架構(ARM 等)通常分別對目標寄存器進行編碼。

Salsa20 核心主要由以下形式的許多更新組成:

x[i] ^= rol32(x[j] + x[k], N);

或者

t = x[j] + x[k];
u = rol32(t, N);
x[i] = x[i] ^ u;

其中 rol32 是 32 位字的左循環。

在 x86(AT&T 語法)中,假設 x

$$ i $$, X$$ j $$, 和 x$$ k $$分別在寄存器 edi、esi 和 edx 中。這可以通過使用 eax 作為臨時寄存器來計算:

lea (%esi,%edx),%eax
rol $N,%eax
xor %eax,%edi

請注意,我們在這裡利用“三操作數 LEA”來添加 esi 和 edx,並將結果放入第三個寄存器 eax。相反,ROL 和 XOR 是“雙操作數”指令:它們重用一個源寄存器作為目標寄存器,並且它們沒有“三操作數”版本。


如果序列改為

x[i] += rol32(x[j] ^ x[k], N);

或者

t = x[j] ^ x[k];
u = rol32(t, N);
x[i] = x[i] + u;

那麼我們需要一個額外的 MOV 指令來計算臨時寄存器中的第一個 XOR,因為我們將使用 x

$$ j $$和 x$$ k $$稍後我們不能立即銷毀它們:

mov %esi,%eax
xor %edx,%eax
rol $N,%eax
add %eax,%edi

這是一個很小的差異,但 Salsa20 核心的設計目的是快速且對性能至關重要,以便在網路上以理想的線速處理數據。當然,為了獲得真正的性能,您會在 x86 上使用 CPU 的矢量單元(SSE 或 AVX),所以今天這在很大程度上是一個有爭議的問題。

引用自:https://crypto.stackexchange.com/questions/102307