密碼學/RadioGatún
本文介紹了一種名為**RadioGatún**的加密演算法。為了充分理解本文,讀者需要理解以下概念
- 二進位制數為了最大限度地提高效能,RadioGatún直接使用二進位制數
- 十六進位制數用於說明演算法的某些部分
- 按位邏輯運算 RadioGatún使用按位取反、按位或和按位異或
- 位旋轉 RadioGatún使用迴圈旋轉
- 密碼雜湊 RadioGatún是一種(據我們所知)安全的密碼雜湊
- 偽隨機數生成器 RadioGatún也作為一個安全的隨機數生成器
- 讀者應該熟悉至少一門程式語言,該語言可以執行 RadioGatún 執行的按位操作。
RadioGatún 是 Keccak 的直接前身,Keccak 是 SHA-3 雜湊標準。它是現存速度最快的雜湊之一:64 位版本的 RadioGatún 與 Blake2b 的速度大致相同,而 32 位版本的 RadioGatún 的速度與 Blake2s 的速度大致相同。雖然 Blake2 的可變長度輸出被新增為附加功能,但 RadioGatún 具有固有的可變長度支援,既可以作為密碼雜湊,也可以作為流密碼。
RadioGatún 是現存最古老的安全可變長度雜湊;它自 2006 年起就存在,截至 2020 年,尚無已知的攻擊削弱其安全宣告。MD5 在釋出後 12 年內就被破解;RadioGatún 存在的時間更長,但看起來仍然安全。
32 位版本似乎提供了 304 位的安全保障;64 位版本看起來提供了 608 位的安全保障。換句話說,32 位版本對於 256 位雜湊來說足夠安全,而 64 位版本可以生成 512 位雜湊。
下面的程式碼使用多個數組來更改 RadioGatún 的狀態。陣列從零開始索引;這意味著陣列的第一個元素的索引為 0 而不是 1。我們不會使用 i[1]、i[2] 和 i[3](從一開始索引的陣列)來表示包含 3 個字的陣列,而是使用 i[0]、i[1] 和 i[2] 來表示。
由於 RadioGatún 直接操作二進位制數,我們有時會將數字以十六進位制格式表示。在這種情況下,我們在數字的開頭加上“0x”。例如:0x07 是 7;0x10 是 16。
在本頁中,位元組始終為 8 位。字可以是 32 位或 64 位,具體取決於使用的 RadioGatún 版本。
RadioGatún 是一種在 21 世紀初 20 年代中期設計的密碼,當時伺服器執行著 32 位和 64 位作業系統的混合體,大多數桌上型電腦仍然執行著 32 位系統,並且在任何手持電話執行 64 位程式碼之前很久。考慮到這一點,該密碼具有不同的模式來支援 32 位和 64 位操作。還有一些非常小的版本可以簡化密碼分析:研究 RadioGatún 安全性的研究人員可以分析 1 位或 2 位版本(截至 2018 年,已被破解的最大 RadioGatún 變體是 2 位變體)。
雖然 RadioGatún 支援 8 位和 16 位,但 8 位版本可能太小而無法保證安全,而 16 位版本可能太小。考慮到這一點,我們只關注 RadioGatún 的 32 位和 64 位變體。
RadioGatún 使用 58 個字(32 位或 64 位,具體取決於我們正在檢視的 RadioGatún 變體)來儲存其狀態。在本文件的其餘部分,“字”是指 32 位或 64 位數字,具體取決於正在使用的 RadioGatún 變體。
要初始化 RadioGatún 的狀態,所有 58 個字都將重置為值 0。
RadioGatún 將其狀態儲存在兩個部分中:39 個字儲存在傳送帶上,傳送帶可以視覺化為三行,每行 13 個字。磨坊有 19 個字寬。RadioGatún 的某些實現使用一個額外的字來儲存傳送帶,這有利於程式碼大小最佳化。
雖然RadioGatún 規範將“傳送帶”和“磨坊”操作視為獨立的,但它們同時完成,因此,在本檔案中,我們將考慮一個組合的傳送帶磨坊操作。這是 RadioGatún 演算法的核心,RadioGatún 的所有部分(輸入對映、輸入結束後的 RadioGatún 混合以及偽隨機輸出位的生成)都使用相同的傳送帶磨坊函式。
RadioGatún 規範將磨坊視為三個陣列,每個陣列包含 13 個元素;在這裡,我們將磨坊視為一個包含 40 個字的陣列。此外,本書中操作的順序與規範中描述的順序不同。
此操作類似於攪拌機,以一種既可預測又據信具有密碼安全性的方式混合 RadioGatún 狀態的位。
在傳送帶到磨坊的向前饋送中,我們用傳送帶中的 12 個字異或磨坊中的 12 個字,如下所示
- 磨坊的第一個詞(在陣列索引從零開始的程式語言中,元素 0)與磨坊的第二個詞(元素 1)進行異或運算;結果詞儲存為皮帶中的元素 0。
- 皮帶的元素 14 與磨坊的元素 2 進行異或運算。
- 皮帶的元素 28 與磨坊的元素 3 進行異或運算。
- 皮帶的元素 3 與磨坊的元素 4 進行異或運算。
- 皮帶的元素 17 與磨坊的元素 5 進行異或運算。
- 皮帶的元素 31 與磨坊的元素 6 進行異或運算。
- 皮帶的元素 6 與磨坊的元素 7 進行異或運算。
- 皮帶的元素 20 與磨坊的元素 8 進行異或運算。
- 皮帶的元素 34 與磨坊的元素 9 進行異或運算。
- 皮帶的元素 9 與磨坊的元素 10 進行異或運算。
- 皮帶的元素 23 與磨坊的元素 11 進行異或運算。
- 皮帶的元素 37 與磨坊的元素 12 進行異或運算。
這可以用以下虛擬碼來表示:
For a = 0 to 11 { # "a" has the values (0,1,2,3,4,5,6,7,8,9,10,11) in this loop
belt[a + ((a % 3) * 13)] = belt[a + ((a % 3) * 13)] ^ mill[a + 1]
}
這裡,% 是模運算:除法後的餘數(例如:5 模 3 是 2;11 模 4 是 3)
^ 是異或運算
* 是乘法
+ 是加法
在主要的磨坊操作中,我們對磨坊中的詞執行一系列操作,並將結果放入一個名為“t”的包含 19 個詞的臨時陣列中。
我們將旋轉常數“r”設定為 0。
我們對“a”從 0 到 18(包括 18)進行 19 次以下操作:
- 我們將“a”加到“r”上。
- 我們將“r”對正在使用的 RadioGatún 變體的詞大小進行模運算(對於 RadioGatún[32],19 個旋轉值是 [0, 1, 3, 6, 10, 15, 21, 28, 4, 13, 23, 2, 14, 27, 9, 24, 8, 25, 11];對於 RadioGatún[64],是 [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43])。
- 我們將索引“i”設定為“a”乘以 7。
- 我們將“i”對 19(磨坊寬度)進行模運算(19 個“i”值是 [0, 7, 14, 2, 9, 16, 4, 11, 18, 6, 13, 1, 8, 15, 3, 10, 17, 5, 12])。
- 我們將“k”設定為磨坊索引“i”。
- 我們將索引“ia”設定為“i”加 1,模 19。“模 19”在這裡意味著,如果“i”的值是 18,我們不將“ia”設定為 19,而是設定為 0。
- 我們將索引“ib”設定為“i”加 2,模 19。“模 19”在這裡意味著,如果 i + 2 是 19 或更高,我們從“i”中減去 19:如果“i”是 17,那麼“ib”將是 0(而不是 19);如果“i”是 18,那麼“ib”將是 1(而不是 20)。
- 我們將磨坊元素“ib”複製到“mb”中。
- 我們對“mb”進行按位取反操作(我們將每個 0 位變成 1,將每個 1 位變成 0)。
- 我們將磨坊元素“ia”複製到“ma”中。
- 我們對“ma”和“mb”進行按位或運算,並將結果放入“mc”中。
- 我們將“mc”與磨坊元素“i”進行異或運算,並將結果放入臨時陣列“t”中,其索引為“a”。
- 我們將臨時陣列“t”中索引為“a”的元素向右旋轉“r”位。
這可能看起來像以下虛擬碼
r = 0
for a = 0 to 18 {
r = r + a
r = r % wordsize # 32 for 32-bit RadioGatún, 64 for 64-bit RadioGatún
i = a * 7
i = i % 19 # Mill width
k = mill[i]
k = k ^ (mill[(i + 1) % 19] | (~mill[(i + 2) % 19]))
t[a] = rotate_right(k, r)
}
運算子與上面相同;此外,~ 是按位取反
rotate_right 是迴圈向右旋轉。例如,對於 32 位 RadioGatún,rotate_right 可能看起來像 C 中的以下程式碼
uint32_t rotate_right(uint32_t k, int r) {
return k>>r|k<<((32-r)%32);
}
現在,我們已經對磨坊中的元素執行了一些操作並將它們放入了 19 個詞的臨時陣列“t”中,我們現在可以根據“t”中儲存的值來更新實際的磨坊。
對於“a”從 0 到 18(包括 18)的每個值
- “i1”將是“a”加 1,模 19。
- “i2”將是“a”加 4,模 19。
- 將磨坊元素“a”設定為“t”陣列中元素“a”的值。
- 將磨坊元素“a”與“t”陣列中元素“i1”的值進行異或運算。
- 將磨坊元素“a”與“t”陣列中元素“i2”的值進行異或運算。
虛擬碼
for a = 0 to 18 {
mill[a] = t[a] ^ t[(a + 1) % 19] ^ t[(a + 4) % 19]
}
我們現在旋轉皮帶。在 RadioGatún 規範中,這被描述為將皮帶的每一行都向右移動一個位置。所有詞都向右移動一個位置,就像傳送帶一樣,除了最右邊的詞會移動到最左邊。皮帶包含三行,每行 13 個元素;我們分別對三行進行此旋轉操作。
為了使程式碼更簡單、更小,我們可以將皮帶視為包含 40 個(而不是 39 個)元素的陣列,然後將所有元素向右移動一個位置。完成此操作後,我們將三個值向下移動皮帶,使皮帶變成迴圈的。
對於“i”從 38 到 0(包括 0;請注意,我們從 38 開始,然後向下到 0)
- 將“i”加 1 並賦予它值“i1”(因此 38 變成 39,37 變成 38,依此類推)
- 將索引為“i1”的皮帶元素賦值為索引為“i”的皮帶元素的值。
我們從 38 向下到 0 而不是從 0 向上到 39 的原因是,如果我們遞增而不是遞減“i”,磨坊中的所有元素將具有相同的值(磨坊元素 0),從而破壞磨坊。
將磨坊中的所有元素向上移動一個位置後,我們現在將三個元素向下移動。
對於“i”從 0 到 2(包括 2)
- “i0”是“i”乘以 13(皮頻寬度)。
- “i1”是“i0”加 13。
- 取皮帶元素“i0”並將皮帶元素“i1”的值賦值給它。
第二個迴圈使皮帶成為三個 13 個元素的迴圈皮帶。
以上兩個步驟可以用以下虛擬碼來完成
for a = 38 to 0 step -1 { # "step -1" makes it clear we're moving down from 38 instead of up from 0
belt[a + 1] = belt[a]
}
for a = 0 to 2 {
belt[(a + 1) * 13] = belt[a * 13]
}
請注意,RadioGatún 的速度最佳化實現(例如 Thomas Pornin 在 sphlib 中編寫的實現)不旋轉皮帶;相反,它們執行 13 個不同的 beltmill 函式版本,透過改變相互作用的元素而不是移動 39 個元素來實現。
iota 步只是將磨坊中的第一個詞(元素 0)與數字 1 進行異或運算。
虛擬碼
mill[0] = mill[0] ^ 1
請注意,在 Keccak 中,iota 步要複雜得多。
為了完成 beltmill 函式,我們將磨坊中的三個詞與皮帶中的三個詞進行異或運算,並將結果儲存在磨坊詞中。
- 磨坊元素 13(磨坊中的第 14 個元素)與皮帶元素 0(磨坊最下面的行的第一個詞)進行異或運算,並將結果儲存在磨坊元素 13 中。
- 磨坊元素 14(磨坊中的第 15 個元素)與皮帶元素 13(磨坊中間行的第一個詞)進行異或運算,並將結果儲存在磨坊元素 14 中。
- 磨坊元素 15(磨坊中的第 16 個元素)與皮帶元素 26(磨坊最上面的行的第一個詞)進行異或運算,並將結果儲存在磨坊元素 15 中。
虛擬碼
mill[13] = mill[13] ^ belt[0] mill[14] = mill[14] ^ belt[13] mill[15] = mill[15] ^ belt[26]
請注意,RadioGatún 的程式碼大小最佳化版本會將此操作放在一個 3 步迴圈中,因為我們可以將皮帶旋轉的第二部分和皮帶到磨坊的操作放在一個小的迴圈中,但是速度最佳化版本會展開迴圈(將迴圈中執行的操作轉換為迴圈外執行的多項操作,以節省處理迴圈所需的 CPU 週期)。
輸入對映步驟是我們獲取任意八位位元組長度的二進位制字串,並使用它來建立 RadioGatún 的狀態。
我們首先檢視 RadioGatún[32](32 位 RadioGatún),在這種情況下,雜湊輸入的長度恰好為 32 位。
首先,我們初始化 RadioGatún:我們將皮帶和磨坊中的所有詞的值設定為 0。完成此操作後,我們將執行以下操作(所有這些步驟實際上都是異或運算,但由於我們是對值 0 進行異或運算,因此它等同於將它們設定為所需的值)。
- 我們將皮帶的第一個元素(皮帶元素 0)設定為 32 位雜湊輸入。
- 我們將磨坊的第 17 個位元組(磨坊元素 16)設定為相同的 32 位雜湊輸入。
- 我們將皮帶的第 14 個位元組(皮帶元素 13,或者也可以說是皮帶第二行的第一個詞)設定為二進位制 1。
- 我們將磨坊的第 18 個位元組(磨坊元素 17)也設定為值 1。
瞧!我們現在將 32 位雜湊輸入(或者也可以說是“種子”)放入 RadioGatún 中。
虛擬碼
function initRadioGatun32(int32bit a) {
for b = 0 to 18 {
mill[b] = 0
}
for b = 1 to 39 {
belt[b] = 0
}
mill[16] = a
belt[0] = a
mill[17] = 1
belt[13] = 1
}
將此 32 位值放入 RadioGatún 狀態(皮帶和磨坊)後,我們現在可以執行“空白輪”步驟。
輸入字串結束後,RadioGatún 執行 18 輪空白輪:18 次 Beltmill() 函式迭代。
虛擬碼
for a = 1 to 18 {
Beltmill() # As already described above
}
執行完空白輪後,跳轉到後面的“生成輸出”部分。
RadioGatún 不僅支援 32 位輸入,它支援從 0 開始的任何位元組數的輸入。接下來我們將介紹如何處理其他長度的輸入。
RadioGatún 假設在小端序處理器上執行(或者更準確地說,用於生成參考測試向量的參考實現是在小端序機器上執行的)。考慮到這一點,8 位位元組被轉換為 32 位或 64 位字(取決於我們使用的是 32 位還是 64 位變體),第一個位元組被設定為最低有效位。
換句話說,如果 RadioGatún 給定字串“124”,它由位元組(以十六進位制表示)0x31、0x32 和 0x34 組成,這將被 RadioGatún[32](32 位版本)轉換為 0x01343231,並被 RadioGatún 的 64 位版本轉換為 0x0000000001343231。
這裡,給定 RadioGatún 的第一個位元組被設定為 RadioGatún 使用的字的最低(最低有效)八個位元組。
知道自己在小端序機器上執行的 RadioGatún 的速度最佳化版本可以直接從記憶體中讀取字,以便它們影響狀態。
您可能還會注意到,位元組 0x01 被放置在上面字串的末尾;這是一個填充位元組,用於讓 RadioGatún 知道字串在哪裡結束。這個填充位元組保護 RadioGatún 免受一些安全攻擊。因此,如果我們的字串是三個位元組的字串“124”,或者 0x31 0x32 0x34,它將變成 0x31 0x32 0x34 0x01,然後被轉換為小端序數字,比如 0x01343231。如果給 RadioGatún 一個值為 0x01 的單位元組字串,這將被轉換為 0x01 0x01,然後進行小端序轉換。
RadioGatún 可以讀取任何任意二進位制字串,包括包含 0x00(NULL)、0x01 等的字串,只要字串的長度是 8 的倍數(0 位長、8 位長、16 位長、24 位長等);RadioGatún 不支援其他輸入長度的原因是,它的填充行為沒有完全定義,並且沒有官方的測試向量不是八位長的倍數。
一旦輸入字串被轉換為小端序字,我們就取三個字,並將它們與 RadioGatún 狀態進行異或運算,如下所示
- 我們將這三個字命名為“w1”、“w2”和“w3”。例如,如果 RadioGatún[32] 給定字串“12345678901”作為輸入,“w1”將具有值 0x34333231,“w2”將是 0x38373635,“w3”將是 0x01313039。如果字串更短,例如“1”(0x31),我們將用 0 填充:”w1“將是 0x00000131,”w2“和”w3“將簡單地是 0x00000000;如果使用 RadioGatún[64] 並且字串僅僅是 ASCII 字元“1”,”w1“將是 0x0000000000000131,”w2“和”w3“將是 0x0000000000000000。
- 我們將皮帶的第一個位元組(皮帶元素 0)與“w1”進行異或運算,並將結果放回 belt[0]
- 我們將磨坊的第 17 個位元組(磨坊元素 16)與“w1”進行異或運算,並將結果放回 mill[16]
- 我們將皮帶的第 14 個位元組(皮帶元素 13,或者你可以說,皮帶的第二行的第一個位元組)與“w2”進行異或運算,並將結果放回 belt[13]
- 我們將磨坊的第 18 個位元組(磨坊元素 17)與“w2”進行異或運算,並將結果放回 mill[17]
- 我們將皮帶的第 27 個位元組(皮帶元素 26,或者你可以說,皮帶的頂部的第一個位元組)與“w3”進行異或運算,並將結果放回 belt[26]
- 我們將磨坊的第 19 個位元組(磨坊元素 18)與“w3”進行異或運算,並將結果放回 mill[18]
- 現在我們對 RadioGatún 的狀態執行 Beltmill 函式
如果字串,包括最後的 0x01 填充位元組,被使用完,我們就轉到下一部分。否則,我們向前移動字串 12 或 24 個位元組(取決於我們是在計算 RadioGatún[32] 還是 RadioGatún[64]),並重覆上述步驟。
在這個虛擬碼示例中,我們逐位元組讀取輸入,以使程式碼與端序無關(它在大小端序機器上執行方式相同)。RadioGatunWordSize 指示我們正在實現的 RadioGatún 變體的字大小,可以是 32 或 64;Beltmill() 是前面描述的皮帶磨坊函式
endOfString = False
array inputWords[3]
# Initialize the input words
for i = 0 to 2 {
inputWords[i] = 0
}
i = 0
shift = 0
while(endOfString is False) {
a = getByteFromString()
if(isEndOfString()) {
a = 1
endOfString = True
}
a = shiftLeft(a, shift)
inputWords[i] = inputWords[i] | a # Here, '|' is bitwise "or"
shift = shift + 8
if(shift >= RadioGatunWordSize or endOfString is True) {
belt[i + 16] = belt[i + 16] ^ inputWords[i]
mill[i * 13] = mill[i * 13] ^ inputWords[i]
i = i + 1
shift = 0
if(i >= 3 and endOfString is not True) {
Beltmill()
i = 0
}
}
}
getByteFromString() 是一個從輸入字串中獲取單個八位位元組(8 位位元組)的函式。isEndOfString() 在我們到達輸入字串的末尾時,如果對 getByteFromString() 的最後一次呼叫失敗,則返回 true。
完成此操作後,執行上述 18 輪空白輪,然後轉到後面的“生成輸出”部分,生成 RadioGatún 的雜湊輸出。
由於 RadioGatún 被設計為一個安全的雜湊函式,因此在計算上不可行地找到兩個不同的輸入,它們建立相同的內部狀態。此外,不應該能夠將 RadioGatún 的輸出與實際的隨機位區分開 - 它看起來像是噪聲。即使攻擊者知道他們正在檢視 RadioGatún 生成的位,也不應該能夠預測下一個偽隨機位,除非知道輸入。
執行完空白輪後,我們現在可以輸出 RadioGatun() 磨坊中的字,以生成任意數量的密碼安全隨機數。
過程很簡單
- 我們檢視磨坊中的第二個元素(磨坊元素編號 1),以獲取前 32 位或 64 位隨機輸出,具體取決於我們選擇實現 RadioGatún[32] 還是 RadioGatún[64]
- 我們檢視磨坊中的第三個元素(磨坊元素編號 2),以獲取另外 32/64 位輸出
- 我們執行 Beltmill 操作,如前面所述
- 我們重複上述三個步驟,以獲得任意數量的輸出位
這是一些顯示此過程的虛擬碼
phase = 1 # The word we get from the mill; initial value is one
function getWordFromRadioGatun() {
out = mill[phase]
phase = phase + 1
if(phase > 2) {
phase = 1
Beltmill()
}
return out
}
getWordFromRadioGatun() 如果使用 32 位版本的 RadioGatun,則提供 32 位,如果使用 64 位版本,則提供 64 位。
請注意,為了與參考測試向量相容,需要對數字進行端序交換(或者等效地,磨坊需要被視為小端序系統上的位元組陣列)。
在本示例中,我們使用 RadioGatún[32] 處理字串“1234”。根據參考規範
RadioGatun[32]("1234") = 9EBDD24F469993796C4AAC6A821735A65A3CDEF8A359944CE71F34E7A08E1182
考慮到這一點,執行並完成輸入對映後,皮帶和磨坊如下所示
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0x00000000 0x34333231 0x00000001 0x00000000 1 0x00000000 0x00000000 0x00000000 0x00000000 2 0x00000000 0x00000000 0x00000000 0x00000000 3 0x00000000 0x00000000 0x00000000 0x00000000 4 0x00000000 0x00000000 0x00000000 0x00000000 5 0x00000000 0x00000000 0x00000000 0x00000000 6 0x00000000 0x00000000 0x00000000 0x00000000 7 0x00000000 0x00000000 0x00000000 0x00000000 8 0x00000000 0x00000000 0x00000000 0x00000000 9 0x00000000 0x00000000 0x00000000 0x00000000 10 0x00000000 0x00000000 0x00000000 0x00000000 11 0x00000000 0x00000000 0x00000000 0x00000000 12 0x00000000 0x00000000 0x00000000 0x00000000 13 0x00000000 14 0x00000000 15 0x00000000 16 0x34333231 17 0x00000001 18 0x00000000
在此圖表中,左側的數字是所討論元素的陣列索引。我們不將皮帶視為一個包含 39(或 40)個字的單個數組,而是將皮帶視為包含 13 個字的三行。如果使用將皮帶視為單個數組的程式碼,皮帶行 1 包含皮帶中的元素 0-12,行 2 包含元素 13-25,行 3 包含元素 26-38。
執行完皮帶旋轉後,皮帶和磨坊看起來像這樣(觀察皮帶中元素是如何從第 0 行移動到第 1 行的)
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0x00000000 0x00000000 0x00000000 0x00000000 1 0x00000000 0x34333231 0x00000001 0x00000000 2 0x00000000 0x00000000 0x00000000 0x00000000 3 0x00000000 0x00000000 0x00000000 0x00000000 4 0x00000000 0x00000000 0x00000000 0x00000000 5 0x00000000 0x00000000 0x00000000 0x00000000 6 0x00000000 0x00000000 0x00000000 0x00000000 7 0x00000000 0x00000000 0x00000000 0x00000000 8 0x00000000 0x00000000 0x00000000 0x00000000 9 0x00000000 0x00000000 0x00000000 0x00000000 10 0x00000000 0x00000000 0x00000000 0x00000000 11 0x00000000 0x00000000 0x00000000 0x00000000 12 0x00000000 0x00000000 0x00000000 0x00000000 13 0x00000000 14 0x00000000 15 0x00000000 16 0x34333231 17 0x00000001 18 0x00000000
主磨坊操作以如下方式設定臨時陣列(“t”)中的 19 個元素
0 0xffffffff 1 0xffffffff 2 0xd97999b9 3 0xffffffff 4 0xffffffff 5 0x9b9d9799 6 0xffffffff 7 0xffffffff 8 0xffffffff 9 0xffffffff 10 0xffffffff 11 0xffffffff 12 0xffffffff 13 0xffffffff 14 0xffffffff 15 0xffffffff 16 0xfeffffff 17 0xffffffff 18 0xffffffff
使用這些值更新磨坊後,磨坊和皮帶將看起來像這樣
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xffffffff 0x00000000 0x00000000 0x00000000 1 0xbd1bf1df 0x34333231 0x00000001 0x00000000 2 0xd97999b9 0x00000000 0x00000000 0x00000000 3 0xffffffff 0x00000000 0x00000000 0x00000000 4 0x9b9d9799 0x00000000 0x00000000 0x00000000 5 0x9b9d9799 0x00000000 0x00000000 0x00000000 6 0xffffffff 0x00000000 0x00000000 0x00000000 7 0xffffffff 0x00000000 0x00000000 0x00000000 8 0xffffffff 0x00000000 0x00000000 0x00000000 9 0xffffffff 0x00000000 0x00000000 0x00000000 10 0xffffffff 0x00000000 0x00000000 0x00000000 11 0xffffffff 0x00000000 0x00000000 0x00000000 12 0xfeffffff 0x00000000 0x00000000 0x00000000 13 0xffffffff 14 0xffffffff 15 0xfeffffff 16 0xfeffffff 17 0xd97999b9 18 0xffffffff
iota 步驟隻影響磨坊的第一個元素(使其在這裡變為 0xfffffffe)
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xfffffffe 0x00000000 0x00000000 0x00000000 1 0xbd1bf1df 0x34333231 0x00000001 0x00000000 2 0xd97999b9 0x00000000 0x00000000 0x00000000 3 0xffffffff 0x00000000 0x00000000 0x00000000 4 0x9b9d9799 0x00000000 0x00000000 0x00000000 5 0x9b9d9799 0x00000000 0x00000000 0x00000000 6 0xffffffff 0x00000000 0x00000000 0x00000000 7 0xffffffff 0x00000000 0x00000000 0x00000000 8 0xffffffff 0x00000000 0x00000000 0x00000000 9 0xffffffff 0x00000000 0x00000000 0x00000000 10 0xffffffff 0x00000000 0x00000000 0x00000000 11 0xffffffff 0x00000000 0x00000000 0x00000000 12 0xfeffffff 0x00000000 0x00000000 0x00000000 13 0xffffffff 14 0xffffffff 15 0xfeffffff 16 0xfeffffff 17 0xd97999b9 18 0xffffffff
以上是執行一次 Beltmill 操作後狀態的樣子。以下是再次對其執行 Beltmill() 後它看起來的樣子
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0x40600820 0x00000000 0x00000000 0x00000000 1 0xcc8c4f0c 0xbd1bf1df 0x00000000 0x00000000 2 0x189a1999 0x34333231 0xd97999b8 0x00000000 3 0x089a1999 0x00000000 0x00000000 0xffffffff 4 0xdc8c4f0c 0x9b9d9799 0x00000000 0x00000000 5 0xcc8c4f0c 0x00000000 0x9b9d9799 0x00000000 6 0x10000000 0x00000000 0x00000000 0xffffffff 7 0x99189a19 0xffffffff 0x00000000 0x00000000 8 0x10000000 0x00000000 0xffffffff 0x00000000 9 0x00000000 0x00000000 0x00000000 0xffffffff 10 0x99189a19 0xffffffff 0x00000000 0x00000000 11 0x99189a19 0x00000000 0xffffffff 0x00000000 12 0x46268666 0x00000000 0x00000000 0xfeffffff 13 0x31343332 14 0x00002000 15 0x06468e47 16 0x7712b554 17 0x31341332 18 0x58fa31b8
再執行 16 次(共 18 次 Beltmill() 呼叫)後,它看起來像這樣
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xd9958271 0x4fa9a4eb 0x3a5bda1c 0x599e1cba 1 0x4fd2bd9e 0xf40378f6 0xa5fff169 0xce6dad5a 2 0x79939946 0x7d0e377e 0x72637aad 0x83531eac 3 0xd9acd8da 0xbe8a2a76 0xc9958a5e 0x6a9d5b52 4 0x4a9b1478 0x44a12573 0xc4d346a6 0x0691e902 5 0xdefb4010 0xcfd07457 0x36adb7a1 0x112926ab 6 0x839db45d 0x08bc2beb 0x4cf52045 0x37060596 7 0x9bf58054 0x33bb3e40 0x978cf3fc 0x6452478c 8 0x734beab8 0x7873cf2d 0xbfaa6388 0x8840c4ae 9 0xa4c4d0dd 0x526856e9 0x1e33dbc2 0x80f95c1b 10 0x3fa1dc95 0x9829c411 0x4cd43100 0xfb9eb71a 11 0x0da8e828 0x1891da52 0x4f264567 0xccd49043 12 0x25fd61e7 0x031a49c7 0x5866b7ab 0x7f443d0c 13 0xd247ea91 14 0xb1e8b921 15 0x23154075 16 0x5ad6fbc4 17 0xbbc617dc 18 0x6eb76abb
此時,我們使用磨機索引 1(0x4fd2bd9e)生成前 32 位輸出
9ebdd24f
觀察到已經發生了位元組序交換:第一個位元組現在是第四個位元組,第二個位元組現在是第三個位元組,第三個位元組現在是第二個位元組,最後一個位元組現在是第一個位元組。
雜湊的接下來的 32 位來自磨機索引 2(0x79939946)
46999379
現在我們已經提取了磨機上兩個元素的值以生成一些隨機數,我們再次執行 Beltmill() 操作。 我們將更詳細地研究這一點。
首先,我們執行**皮帶到磨機前饋**,導致
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xd9958271 0x007b1975 0x3a5bda1c 0x599e1cba 1 0x4fd2bd9e 0xf40378f6 0xdc6c682f 0xce6dad5a 2 0x79939946 0x7d0e377e 0x72637aad 0x5affc676 3 0xd9acd8da 0xf4113e0e 0xc9958a5e 0x6a9d5b52 4 0x4a9b1478 0x44a12573 0x1a2806b6 0x0691e902 5 0xdefb4010 0xcfd07457 0x36adb7a1 0x92b492f6 6 0x839db45d 0x9349abbf 0x4cf52045 0x37060596 7 0x9bf58054 0x33bb3e40 0xe4c71944 0x6452478c 8 0x734beab8 0x7873cf2d 0xbfaa6388 0x2c841473 9 0xa4c4d0dd 0x6dc98a7c 0x1e33dbc2 0x80f95c1b 10 0x3fa1dc95 0x9829c411 0x417cd928 0xfb9eb71a 11 0x0da8e828 0x1891da52 0x4f264567 0xe929f1a4 12 0x25fd61e7 0x031a49c7 0x5866b7ab 0x7f443d0c 13 0xd247ea91 14 0xb1e8b921 15 0x23154075 16 0x5ad6fbc4 17 0xbbc617dc 18 0x6eb76abb
接下來我們**旋轉皮帶**
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xd9958271 0x031a49c7 0x5866b7ab 0x7f443d0c 1 0x4fd2bd9e 0x007b1975 0x3a5bda1c 0x599e1cba 2 0x79939946 0xf40378f6 0xdc6c682f 0xce6dad5a 3 0xd9acd8da 0x7d0e377e 0x72637aad 0x5affc676 4 0x4a9b1478 0xf4113e0e 0xc9958a5e 0x6a9d5b52 5 0xdefb4010 0x44a12573 0x1a2806b6 0x0691e902 6 0x839db45d 0xcfd07457 0x36adb7a1 0x92b492f6 7 0x9bf58054 0x9349abbf 0x4cf52045 0x37060596 8 0x734beab8 0x33bb3e40 0xe4c71944 0x6452478c 9 0xa4c4d0dd 0x7873cf2d 0xbfaa6388 0x2c841473 10 0x3fa1dc95 0x6dc98a7c 0x1e33dbc2 0x80f95c1b 11 0x0da8e828 0x9829c411 0x417cd928 0xfb9eb71a 12 0x25fd61e7 0x1891da52 0x4f264567 0xe929f1a4 13 0xd247ea91 14 0xb1e8b921 15 0x23154075 16 0x5ad6fbc4 17 0xbbc617dc 18 0x6eb76abb
以下是我們在執行**主要磨機操作**後臨時陣列“t”的樣子
0 0x166b7dce 1 0x704737f7 2 0xc2dabfab 3 0x6611fd8a 4 0xc296ccc3 5 0xd831c230 6 0x02fe55a3 7 0x0559dc72 8 0xa970aa8c 9 0x0850e341 10 0x5aaa745f 11 0x4c0040be 12 0x651e5e54 13 0xbd57724f 14 0x92d919b3 15 0x0b22ade0 16 0x63d53968 17 0xb25ff79c 18 0xe71f7551
現在我們使用這些值來**更新磨機**
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xa4ba86fa 0x031a49c7 0x5866b7ab 0x7f443d0c 1 0x6aac4a6c 0x007b1975 0x3a5bda1c 0x599e1cba 2 0xa6351782 0xf40378f6 0xdc6c682f 0xce6dad5a 3 0xa1deed3b 0x7d0e377e 0x72637aad 0x5affc676 4 0xb3d7a47f 0xf4113e0e 0xc9958a5e 0x6a9d5b52 5 0xd29f74d2 0x44a12573 0x1a2806b6 0x0691e902 6 0x5d0dfd8e 0xcfd07457 0x36adb7a1 0x92b492f6 7 0xe0293640 0x9349abbf 0x4cf52045 0x37060596 8 0xc43e1799 0x33bb3e40 0xe4c71944 0x6452478c 9 0xefade551 0x7873cf2d 0xbfaa6388 0x2c841473 10 0x84732d52 0x6dc98a7c 0x1e33dbc2 0x80f95c1b 11 0x223cb30a 0x9829c411 0x417cd928 0xfb9eb71a 12 0xbb9c1573 0x1891da52 0x4f264567 0xe929f1a4 13 0x9dd19c60 14 0x7ee4c102 15 0x7e9ce946 16 0xa1cdf903 17 0x979a3d66 18 0x9765f515
**iota**步驟僅影響磨機的字 0
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xa4ba86fb 0x031a49c7 0x5866b7ab 0x7f443d0c 1 0x6aac4a6c 0x007b1975 0x3a5bda1c 0x599e1cba 2 0xa6351782 0xf40378f6 0xdc6c682f 0xce6dad5a 3 0xa1deed3b 0x7d0e377e 0x72637aad 0x5affc676 4 0xb3d7a47f 0xf4113e0e 0xc9958a5e 0x6a9d5b52 5 0xd29f74d2 0x44a12573 0x1a2806b6 0x0691e902 6 0x5d0dfd8e 0xcfd07457 0x36adb7a1 0x92b492f6 7 0xe0293640 0x9349abbf 0x4cf52045 0x37060596 8 0xc43e1799 0x33bb3e40 0xe4c71944 0x6452478c 9 0xefade551 0x7873cf2d 0xbfaa6388 0x2c841473 10 0x84732d52 0x6dc98a7c 0x1e33dbc2 0x80f95c1b 11 0x223cb30a 0x9829c411 0x417cd928 0xfb9eb71a 12 0xbb9c1573 0x1891da52 0x4f264567 0xe929f1a4 13 0x9dd19c60 14 0x7ee4c102 15 0x7e9ce946 16 0xa1cdf903 17 0x979a3d66 18 0x9765f515
**皮帶到磨機**操作影響磨機中的元素 13 到 15
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0xa4ba86fb 0x031a49c7 0x5866b7ab 0x7f443d0c 1 0x6aac4a6c 0x007b1975 0x3a5bda1c 0x599e1cba 2 0xa6351782 0xf40378f6 0xdc6c682f 0xce6dad5a 3 0xa1deed3b 0x7d0e377e 0x72637aad 0x5affc676 4 0xb3d7a47f 0xf4113e0e 0xc9958a5e 0x6a9d5b52 5 0xd29f74d2 0x44a12573 0x1a2806b6 0x0691e902 6 0x5d0dfd8e 0xcfd07457 0x36adb7a1 0x92b492f6 7 0xe0293640 0x9349abbf 0x4cf52045 0x37060596 8 0xc43e1799 0x33bb3e40 0xe4c71944 0x6452478c 9 0xefade551 0x7873cf2d 0xbfaa6388 0x2c841473 10 0x84732d52 0x6dc98a7c 0x1e33dbc2 0x80f95c1b 11 0x223cb30a 0x9829c411 0x417cd928 0xfb9eb71a 12 0xbb9c1573 0x1891da52 0x4f264567 0xe929f1a4 13 0x9ecbd5a7 14 0x268276a9 15 0x01d8d44a 16 0xa1cdf903 17 0x979a3d66 18 0x9765f515
此時,我們從磨機中取字 1 和 2 來生成 64 位雜湊輸出
6c4aac6a821735a6
然後我們再次執行 Beltmill(),導致
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0x6cf36fda 0x1891da52 0x4f264567 0xe929f1a4 1 0xf8de3c5a 0x69b603ab 0x5866b7ab 0x7f443d0c 2 0x4c9459a3 0x007b1975 0x9c6ecd9e 0x599e1cba 3 0x54ab7f1f 0xf40378f6 0xdc6c682f 0x6fb34061 4 0x467fcf23 0xced99301 0x72637aad 0x5affc676 5 0xd40be986 0xf4113e0e 0x1b0afe8c 0x6a9d5b52 6 0x07c891d4 0x44a12573 0x1a2806b6 0x5b9c148c 7 0xdf077459 0x2ff94217 0x36adb7a1 0x92b492f6 8 0x7cfc3d41 0x9349abbf 0x88cb37dc 0x37060596 9 0xc0b4f9dd 0x33bb3e40 0xe4c71944 0x8bffa2dd 10 0x5e7d770b 0xfc00e27f 0xbfaa6388 0x2c841473 11 0x286065c7 0x6dc98a7c 0x3c0f68c8 0x80f95c1b 12 0xf47debb2 0x9829c411 0x417cd928 0x4002a269 13 0x9c7f8208 14 0x7173015d 15 0x49e3be00 16 0x4927ddf9 17 0x5fe72eb5 18 0x2af7cf5f
為我們提供這些 64 位雜湊輸出
5a3cdef8a359944c
為了生成所需的 256 位雜湊的最後 64 位,我們最後一次執行 Beltmill()
Mill Belt Row 1 Belt Row 2 Belt Row 3 0 0x7ef726d9 0x9829c411 0x417cd928 0x4002a269 1 0xe7341fe7 0xe04fe608 0x4f264567 0xe929f1a4 2 0x82118ea0 0x69b603ab 0x14f2ee08 0x7f443d0c 3 0xb29a8d55 0x007b1975 0x9c6ecd9e 0x0d3563a5 4 0x7b4ebd5a 0xb27cb7d5 0xdc6c682f 0x6fb34061 5 0xfec38e38 0xced99301 0xa668932b 0x5affc676 6 0xf95a2809 0xf4113e0e 0x1b0afe8c 0x6d55ca86 7 0xb84b5869 0x9ba6512a 0x1a2806b6 0x5b9c148c 8 0x2ffcf15a 0x2ff94217 0x4a518ae0 0x92b492f6 9 0x235557d9 0x9349abbf 0x88cb37dc 0xf7b2fc4b 10 0x7658fde8 0x6dc6494b 0xe4c71944 0x8bffa2dd 11 0xc8320830 0xfc00e27f 0x97ca064f 0x2c841473 12 0xc39a12ae 0x6dc98a7c 0x3c0f68c8 0x7484b7a9 13 0x4801294c 14 0x4f6ee74f 15 0x82e8af69 16 0x63210515 17 0x2b657fd0 18 0xc6c57d5f
並以如下方式完成我們的雜湊
e71f34e7a08e1182
如果需要更多偽隨機數,我們可以根據需要執行 Beltmill() 來生成更多數字。