XMR門羅幣新算法:RandomX設計說明(翻譯,下篇)

(原文地址:https://github.com/tevador/RandomX/blob/master/doc/design.md, 總共有3章以及附錄,本篇是第3章以及附錄)

3.自定義函數
3.1 AesGenerator1R
    AesGenerator1R被設計成能儘可能快地生成僞隨機數據去填充暫存器。它利用了現代CPU中硬件加速的AES。每16字節的輸出只執行一次AES輪,這導致在大多數現代CPU中吞吐量可超過20 GB/s。
    AesGenerator1R提供了一個良好的輸出分佈,但前提是由足夠“隨機”的初狀態進行初始化(參見附錄F)。

3.2 AesGenerator4R
    AesGenerator4R使用4個AES輪去生成僞隨機數據,用於程序緩衝區初始化。由於2個AES輪足以對所有輸入比特位產生完全的雪崩效應[28],AesGenerator4R有良好的統計特性(見附錄F),同時保持非常出色的性能。
    這個生成器的可逆特性不是問題,因爲生成器狀態總是使用不可逆哈希函數(Blake2b)的輸出進行初始化。

3.3 AesHash1R
    AesHash被設計成能儘可能快地計算出暫存器指紋。它將暫存器解釋爲一組AES輪密鑰,因此它相當於32768輪的AES加密。結束時再執行兩輪額外的AES運算,以確保暫存器每個lane中所有比特位都能產生雪崩效應。
    AesHash1R的可逆特性不是問題,主要有兩個原因:

  •     不可能直接控制AesHash1R的輸入。
  •     AesHash1R的輸出被傳遞給Blake2b哈希函數,而它是不可逆的。

3.4 超標量哈希
    超標量哈希被設計成在CPU等待從DRAM加載數據時消耗儘可能多的能量。170週期的目標延遲對應普通DRAM 40-80 ns的延遲和2-4 GHz的時鐘頻率。被設計成用於輕量模式挖礦,並帶有低延遲內存的ASIC設備,在計算數據集項時會受制於超標量哈希造成的瓶頸,它們的效率也會被超標量哈希的高功耗破壞。
    超標量哈希函數平均包含450條指令,其中155條是64位乘法。平均而言,最長依賴鏈的長度是95條指令。設計用於輕量模式挖礦的ASIC設備,帶有256MiB的片上內存,所有操作都是1週期的延遲。假設可無限並行,則平均需要95 * 8 = 760個週期來構建一個數據集項。它將對每個數據集項執行155 * 8 = 1240次64位乘法,這將消耗與從DRAM加載64字節內容差不多的能量。


附錄
A. 鏈式VM執行的效果

    第1.2章描述了爲什麼N個隨機程序被串聯起來,以防止搜索“簡單”程序的挖礦策略。RandomX使用的值爲N = 8.
    讓我們定義Q爲使用過濾器的策略中可接受程序的比例。例如,Q = 0.75意味着25%的程序被拒絕。
    對於N = 1,沒有浪費掉的程序執行,唯一的成本是程序生成和過濾器本身。下面的計算假設這些成本爲零,僅有的實際成本是程序執行。然而,這是一種簡化,因爲RandomX中的程序生成不是毫無代價的(第一個程序生成需要完全初始化暫存器),但它描述了對攻擊者而言的最佳情況。
    對於N > 1,第一個程序通常可以被過濾掉,但是在(第一個)程序執行之後,下一個程序有1- Q的機會被拒絕,於是我們浪費了一次程序的執行。
    對於N個程序鏈式執行,鏈中所有程序都可以接受的概率只有Q^N。然而,在每次嘗試尋找這樣的鏈時,我們都會浪費一些程序的執行。對於N = 8,每次嘗試浪費的程序數等於(1-Q)*(1+2*Q+3*Q^2+4*Q^3+5*Q^4+6*Q^5+7*Q^6) = (7*Q^8-8*Q^7+1)/(1-Q) (Q = 0.75時,約等於2.5)。
讓我們考慮3種挖礦策略:
 
策略I
誠實的礦工不拒絕任何程序(Q = 1)。
策略II
礦工使用優化的定製硬件,無法執行25%的程序(Q = 0.75),但它支持的程序可以快50%地執行。
策略III
礦工可以執行所有的程序,但拒絕最慢的25%的程序作爲鏈中第一個程序。這爲鏈中第一個程序提供了5%的性能增長(與附錄C中的運行時間分佈相匹配)。

結果
    下表列出了上述3種策略和不同N值時的結果。N(I)、N(II)和N(III)三欄列出了每種策略平均要執行多少個程序才能得到一個有效的哈希結果(包括在拒絕的鏈中浪費的程序)。速度(I)、速度(II)和速度(III)三欄列出了相對於策略I的平均挖礦性能。

N N(I) N(II) N(III) 速度(I) 速度(II) 速度(III)
1 1 1 1 1.00 1.50 1.05
2 2 2.3 2 1.00 1.28 1.02
4 4 6.5 4 1.00 0.92 1.01
8 8 27.0 8 1.00 0.44 1.00

    儘管對於挑選的程序有50%的性能優勢,N = 8時,策略II的執行速度將不到誠實礦工速度的一半。策略III的統計優勢很小,當N = 8時可以忽略不計。

B. 性能仿真
    正如2.7章中所述,RandomX旨在利用現代高性能CPU的複雜設計。爲了評估超標量、亂序和推測執行的影響,我們執行了一個簡化的CPU仿真。源代碼可以在perf-simulation.cpp中找到。

CPU模型
    模型CPU使用一個3階段流水線來實現每週期一條指令的理想吞吐量:
                                        (1)                     (2)              (3)
                            指令預取和解碼 ---> 內存訪問 ---> 執行

這三個階段是:
    1.指令預取和解碼。這個階段從程序緩衝區加載指令並解碼指令操作和操作數。
    2.內存訪問。如果此指令使用內存操作數,此階段它會從暫存器載入。這包括內存地址的計算。存儲也在這個階段執行。地址寄存器的值在這個階段必須是可用的。
    3.執行。此階段使用前一階段取到的操作數執行指令,並將結果寫入寄存器文件。
請注意,這是一個樂觀的短流水線,不允許非常高的時鐘速度。使用更長流水線的設計將顯著增加推測執行的好處。

超標量執行
我們的模型CPU包含兩種組件:

  •     執行單元(EXU)——用於執行實際的整數或浮點運算。除了ISTORE外,所有RandomX指令必須在流水線第三階段使用一個執行單元。所有操作都被認爲只需要一個時鐘週期。
  •     內存單元(MEM)——用於加載和存儲到暫存器。所有內存指令(包括ISTORE)在流水線第二階段使用一個內存單元。

    超標量設計將包含多個執行或內存單元,以提高性能。

亂序執行
仿真模型支持兩種設計:
    1.順序——所有指令都是按照它們在程序緩衝區中出現的順序執行的。如果遇到依賴項或所需的EXU/MEM單元不可用,此設計將導致暫停。
    2.亂序——不按程序順序執行指令,但是當一條指令的操作數已準備好並且需要的EXU/MEM單元可用時,就可以執行該指令。

分支處理
仿真模型支持兩種類型的分支處理:
    非推測——當遇到分支時,流水線就會暫停。這通常會給每個分支增加3個週期的代價。
    推測——所有分支都被預測爲不會執行,如果發生錯誤預測(概率爲1/256),流水線將被刷新。

結果
以下10種設計進行了模擬,並測量了執行一個RandomX程序(256條指令)的平均時鐘週期數。

設計 超標量配置 重新排序 分支處理

執行時間

(週期數)

IPC
#1 1 EXU + 1 MEM 順序 非推測 293 0.87
#2 1 EXU + 1 MEM 順序 推測 262 0.98
#3 2 EXU + 1 MEM 順序 非推測 197 1.3
#4 2 EXU + 1 MEM 順序 推測 161 1.6
#5 2 EXU + 1 MEM 亂序 非推測 144 1.8
#6 2 EXU + 1 MEM 亂序 推測 122 2.1
#7 4 EXU + 2 MEM 順序 非推測 135 1.9
#8 4 EXU + 2 MEM 順序 推測 99 2.6
#9 4 EXU + 2 MEM 亂序 非推測 89 2.9
#10 4 EXU + 2 MEM 亂序 推測 64 4.0

    超標量、無序和推測執行設計的好處被清楚地展現出來。

C. RandomX運行時間分佈
    運行時間的數值是在AMD Ryzen 7 1700上測量的,運行在3.0GHz下,使用一個核心。測量程序執行和驗證時間的源代碼可以在runtime-distr.cpp中找到。測量x86 JIT編譯器性能的源代碼可以在jit-performance.cpp中找到。

快速模式-程序執行
    下圖顯示了單個VM程序(在快速模式下)的運行時間分佈。這包括:程序生成、JIT編譯、VM執行和寄存器文件的Blake2b哈希計算。測出程序生成和JIT編譯要消耗3.6μs /程序。

    AMD Ryzen 7 1700在快速模式下(使用1線程)每秒可以計算625次哈希,這意味着一個哈希結果需要1600μs(1.6ms)。這包括(近似):

  •     1480μs用於VM執行(8個程序)
  •     45μs用於用於初始暫存器填充(AesGenerator1R)。
  •     45μs用於最終的暫存器哈希(AesHash1R)。
  •     30μs用於程序生成和JIT編譯(8個程序)

    這給出了頭部的總佔比爲7.5% ((45+45+30)/1600=7.5%,不包括VM執行的每次哈希消耗時間)。

輕量模式-驗證時間
    下圖顯示了使用輕量模式計算1個哈希結果的時間分佈。大多數時間花費在執行數據集項超標量哈希的計算上(14.8 ms中的13.2 ms)。平均驗證時間正好匹配CryptoNight算法的性能。

D.暫存器熵分析
    8次程序執行後的暫存器的平均熵由LZMA壓縮算法粗略估算:
    1.計算哈希結果,並將最終的暫存器內容以帶“.spad”擴展名的文件寫入磁盤 (源代碼:scratchpad-entropy.cpp)
    2.文件被7-Zip [29]在極限壓縮模式下進行壓縮:7z.exe a -t7z -m0=lzma2 -mx=9 scratchpads.7z*.spad
    壓縮文件的大小大約是未壓縮暫存器文件大小的99.98%。這表明在VM執行期間,暫存器保持了較高的熵。

E.超標量哈希分析
    超標量哈希是RandomX用來生成數據集項的自定義函數。它操作8個整數寄存器,並使用隨機指令序列。大約1/3的指令是乘法。
    下圖顯示了超標量哈希對於改變輸入寄存器的單個比特位的敏感性:

    這表明,超標量哈希對高比特位的敏感度較低,對最低比特位的敏感度更低。敏感度最高的是第3-53位(包括)。
    在計算數據集項時,第一個超標量哈希的輸入僅依賴於項的編號。爲確保結果的良好分佈,選擇了本說明書第7.3節中描述的常量,以便爲0-34078718範圍內的所有項目編號(數據集包含34078719個項目)提供惟一的第3-53位值。所有編號的數據集項的所有初始寄存器值都經過了檢查,以確保每個寄存器的3-53位是唯一的,沒有碰撞(源代碼:superscalar-init.cpp)。雖然這對於從超標量哈希函數中獲得惟一輸出而言,並不是嚴格必需的,但這是一種安全預防措施,可以減輕隨機生成的超標量哈希實例的非完美雪崩特性。

F. 隨機數生成器的統計檢驗
    AesGenerator1R和AesGenerator4R均使用TestU01庫[30]進行測試,該庫用於隨機數生成器的經驗測試。源代碼可以在rng-tests.cpp中找到。
    該測試從每個生成器的輸出中抽取大約200MB(“小碎片”測試)、500GB(“碎片”測試)或4TB(“大碎片”測試)的樣本。這比RandomX中生成的數量要多得多(AesGenerator4R是2176字節,AesGenerator1R是2MiB),因此,未通過本測試並不一定意味着生成器不適合它們的使用場景。

AesGenerator4R
當使用Blake2b哈希函數初始化時,此生成器通過了“大碎片”套件中的所有測試:

$ bin/rng-tests 1
state0 = 67e8bbe567a1c18c91a316faf19fab73
state1 = 39f7c0e0a8d96512c525852124fdc9fe
state2 = 7abb07b2c90e04f098261e323eee8159
state3 = 3df534c34cdfbb4e70f8c0e1826f4cf7
…
========= Summary results of BigCrush ========
Version:          TestU01 1.2.3
Generator:        AesGenerator4R
Number of statistics: 160
Total CPU time:  02:50:18.34
All tests were passed

即使初始狀態設置爲全0,生成器也能通過“碎片”套件中的所有測試。

$ bin/rng-tests 0
state0 = 00000000000000000000000000000000
state1 = 00000000000000000000000000000000
state2 = 00000000000000000000000000000000
state3 = 00000000000000000000000000000000
…
========= Summary results of Crush =========
Version:            TestU01 1.2.3
Generator:          AesGenerator4R
Number of statistics: 144
Total CPU time:    00:25:17.95
All tests were passed

AesGenerator1R
使用Blake2b哈希函數初始化時,生成器通過了“碎片”套件中的所有測試。

$ bin/rng-tests 0
state0 = 67e8bbe567a1c18c91a316faf19fab73
state1 = 39f7c0e0a8d96512c525852124fdc9fe
state2 = 7abb07b2c90e04f098261e323eee8159
state3 = 3df534c34cdfbb4e70f8c0e1826f4cf7
…
========= Summary results of Crush =========
Version:            TestU01 1.2.3
Generator:          AesGenerator1R
Number of statistics: 144
Total CPU time:    00:25:06.07
All tests were passed

當初始狀態設置爲全0時,生成器在“碎片”套件的144個測試中有1個測試失敗:

$ bin/rng-tests 0
state0 = 00000000000000000000000000000000
state1 = 00000000000000000000000000000000
state2 = 00000000000000000000000000000000
state3 = 00000000000000000000000000000000
…
========= Summary results of Crush =========
Version:          TestU01 1.2.3
Generator:        AesGenerator1R
Number of statistics:  144
Total CPU time:   00:26:12.75
The following tests gave p-values outside [0.001, 0.9990]:
(eps  means a value < 1.0e-300):
(eps1 means a value < 1.0e-15):
      Test                          p-value
----------------------------------------------
12  BirthdaySpacings, t = 3        1 -  4.4e-5
----------------------------------------------
All other tests were passed

參考資料:
[1] CryptoNote whitepaper - https://cryptonote.org/whitepaper.pdf
[2] ProgPoW: Inefficient integer multiplications - https://github.com/ifdefelse/ProgPOW/issues/16
[3] Cryptographic Hashing function - https://en.wikipedia.org/wiki/Cryptographic_hash_function
[4] randprog - https://github.com/hyc/randprog
[5] RandomJS - https://github.com/tevador/RandomJS
[6] μop cache - https://en.wikipedia.org/wiki/CPU_cache#Micro-operation_(%CE%BCop_or_uop)_cache
[7] Instruction-level parallelism - https://en.wikipedia.org/wiki/Instruction-level_parallelism
[8] Superscalar processor - https://en.wikipedia.org/wiki/Superscalar_processor
[9] Out-of-order execution - https://en.wikipedia.org/wiki/Out-of-order_execution
[10] Speculative execution - https://en.wikipedia.org/wiki/Speculative_execution
[11] Register renaming - https://en.wikipedia.org/wiki/Register_renaming
[12] Blake2 hashing function - https://blake2.net/
[13] Advanced Encryption Standard - https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
[14] Log-normal distribution - https://en.wikipedia.org/wiki/Log-normal_distribution
[15] CryptoNight hash function - https://cryptonote.org/cns/cns008.txt
[16] Dynamic random-access memory - https://en.wikipedia.org/wiki/Dynamic_random-access_memory
[17] Multi-channel memory architecture - https://en.wikipedia.org/wiki/Multi-channel_memory_architecture
[18] Obelisk GRN1 chip details - https://www.grin-forum.org/t/obelisk-grn1-chip-details/4571
[19] Biryukov et al.: Tradeoff Cryptanalysis of Memory-Hard Functions - https://eprint.iacr.org/2015/227.pdf
[20] SK Hynix 20nm DRAM density - http://en.thelec.kr/news/articleView.html?idxno=20
[21] Branch predictor - https://en.wikipedia.org/wiki/Branch_predictor
[22] Predication - https://en.wikipedia.org/wiki/Predication_(computer_architecture)
[23] CPU cache - https://en.wikipedia.org/wiki/CPU_cache
[24] Cortex-A55 Microarchitecture - https://www.anandtech.com/show/11441/dynamiq-and-arms-new-cpus-cortex-a75-a55/4
[25] AMD Zen+ Microarchitecture - https://en.wikichip.org/wiki/amd/microarchitectures/zen%2B#Memory_Hierarchy
[26] Intel Skylake Microarchitecture - https://en.wikichip.org/wiki/intel/microarchitectures/skylake_(client)#Memory_Hierarchy
[27] Biryukov et al.: Fast and Tradeoff-Resilient Memory-Hard Functions for Cryptocurrencies and Password Hashing - https://eprint.iacr.org/2015/430.pdf Table 2, page 8
[28] J. Daemen, V. Rijmen: AES Proposal: Rijndael - https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf page 28
[29] 7-Zip File archiver - https://www.7-zip.org/
[30] TestU01 library - http://simul.iro.umontreal.ca/testu01/tu01.html

發佈了44 篇原創文章 · 獲贊 96 · 訪問量 35萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章