跳轉到內容

密碼學/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

[編輯 | 編輯原始碼]

一旦輸入字串被轉換為小端序字,我們就取三個字,並將它們與 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。

Beltmill() 的第一次執行

[編輯 | 編輯原始碼]

執行完皮帶旋轉後,皮帶和磨坊看起來像這樣(觀察皮帶中元素是如何從第 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 操作後狀態的樣子。以下是再次對其執行 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

呼叫 Beltmill() 18 次後

[編輯 | 編輯原始碼]

再執行 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() 操作。 我們將更詳細地研究這一點。

再次詳細檢視 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() 以生成更多隨機位

[編輯 | 編輯原始碼]

然後我們再次執行 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() 來生成更多數字。

華夏公益教科書