1. 程式人生 > >1.3.1 區塊鏈中的加密算法——Hash算法(更新)

1.3.1 區塊鏈中的加密算法——Hash算法(更新)

highlight int .net 復制代碼 基本上 實現數據完整性 正常的 叠代 www

  為了為保證存儲於區塊鏈中的信息的安全與完整,區塊鏈中使用了包含密碼哈希函數和橢圓曲線公鑰密碼技術在內的大量的現代密碼學技術,同時,這些密碼學技術也被用於設計基於工作量證明的共識算法並識別用戶。

  在前邊的文章中已經系統的講述了密碼學中的哈希算法,在本節,將會給大家介紹Hash算法在區塊鏈中的應用!


概念回顧

  哈希函數:是一類數學函數,可以在有限合理的時間內,將任意長度的消息壓縮為固定長度的二進制串,其輸出值稱為哈希值,也稱為散列值。

  以哈希函數為基礎構造的哈希算法,在現代密碼學中扮演著重要的角色,常用於實現數據完整性和實體認證,同時也構成多種密碼體制和協議的安全保障。

  碰撞

是與哈希函數相關的重要概念,體現著哈希函數的安全性,所謂碰撞是指兩個不同的消息在同一個哈希函數作用下,具有相同的哈希值。

  哈希函數的安全性是指在現有的計算資源(包括時間、空間、資金等)下,找到一個碰撞是不可行的。


區塊鏈中的加密算法······即將開始

        噔噔、噔···噔···!


比特幣中的加密算法:

  在比特幣系統中使用了兩個密碼學Hash函數,一個是SHA256 RIPEMD160

其中:RIPEMD160主要用於生成比特幣地址,我們著重分析比特幣中用得最多的SHA256算法。

  

SHA歷史介紹:    
    SHA256屬於著名的SHA家族一員。SHA(Secure Hash Algorithm,安全哈希算法)是一類由美國國家標準與技術研究院(NIST)發布的密碼哈希函數。
正式名稱為SHA的第一個成員發布於1993年,兩年之後,著名的SHA
-1發布,之後另外的4種變體相繼發布,包括SHA224、SHA256、SHA384和SHA512,這些
算法也被稱作SHA2。SHA256算法是SHA2算法簇中的一類。對於長度小於264位的消息,SHA256會產生一個256位的消息摘要。SHA256具有密碼哈希函數的一般特性。
技術分享圖片

  

  那麽比特幣中的SHA256又是何方神聖?它的設計原理是什麽?代碼又如何實現呢?

            下面讓我娓娓道來·····


  SHA256又是何方神聖?

  SHA256是構造區塊鏈所用的主要密碼哈希函數。無論是區塊的頭部信息還是交易數據,都使用這個哈希函數去計算相關數據的哈希值,以保證數據的完整性。同時,在比特幣系統中,基於尋找給定前綴的SHA256哈希值,設計了工作量證明的共識機制;SHA256也被用於構造比特幣地址,即用來識別不同的用戶。

  SHA256是一個Merkle-Damgard結構的叠代哈希函數,其計算過程分為兩個階段:消息的預處理和主循環。在消息的預處理階段,主要完成消息的填充和擴展填充,將所輸入的原始消息轉化為n個512比特的消息塊,之後對每個消息塊利用SHA256壓縮函數進行處理。這個計算流程是一個叠代計算的過程,當最後1個消息塊(第n塊)處理完畢以後,最終的輸出值就是所輸入的原始消息的SHA256值。

  在比特幣系統中,SHA256算法的一個主要用途是完成PoW(工作量證明)計算。按照比特幣的設計初衷,PoW要求錢包(節點)數和算力值大致匹配,因為需要通過CPU的計算能力來進行投票。然而隨著人們對SHA256的計算由CPU逐漸升級到GPU,到FPGA,直至到ASIC礦機,這使得節點數和PoW算力也漸漸失配。解決這個問題的一個思路是引入另外的一些哈希函數來實現PoW。

  scrypt算法最早用於基於口令的密鑰生成,該算法進行多次帶參數的SHA256計算,即基於SHA256的消息認證碼計算,這類計算需要大量的內存支持。采用scrypt算法進行PoW計算,將PoW計算由已有的拼算力在一定程度上轉化為拼內存,能夠使得節點數和PoW的計算力的失配現象得到緩解。萊特幣就是采用scrypt算法完成PoW計算的。

  SHA3算法是2012年10月由NIST所選定的下一代密碼哈希算法。在遴選SHA3算法過程中人們提出了一系列的候選算法,包括了BLAKE、Grostl、JH、Keccak、Skein、ECHO、Luffa、BMW、CubeHash、SHAvite、SMID等,最後勝出的是Keccak算法。達世幣(DASH,原名暗黑幣,DarkCoin)定義了順序調用上述11個哈希算法的X11算法,並利用這個算法完成PoW計算。同樣,由於采用了X11算法,使得節點數和PoW的計算力能夠保持一定程度上的匹配。

設計原理

  下面介紹SHA算法計算消息摘要的原理:

  對於任意長度(按bit計算)的消息,SHA256都會產生一個32個字節長度數據,稱作消息摘要。當接收到消息的時候,這個消息摘要可以用來驗證數據是否發生改變,即驗證其完整性。在傳輸的過程中,數據很可能會發生變化,那麽這時候就會產生不同的消息摘要。

  SHA算法有如下特性:
  1. 不可以從消息摘要中復原信息;
  2. 兩個不同的消息不會產生同樣的消息摘要。

  一、術語和概念

  (一)位(Bit),字節(Byte)和字(Word)

  SHA始終把消息當成一個位(bit)字符串來處理。本文中,一個“字”(Word)是32位,而一個“字節”(Byte)是8位。比如,字符串“abc”可以被轉換成一個位字符串:01100001 01100010 01100011。它也可以被表示成16進制字符串:0x616263.

   二、SHA256算法描述

  (一)補位

  信息必須進行補位,以使其長度在對512取模以後的余數是448。也就是說,(補位後的消息長度)Q2 = 448。即使長度已經滿足對512取模後余數是448,補位也必須要進行。

  補位是這樣進行的:先補一個1,然後再補0,直到長度滿足對512取模後余數是448。總而言之,補位是至少補一位,最多補512位。以信息“abc”為例顯示補位的過程。
  
  原始信息:01100001 01100010 01100011

  補位第一步:0110000101100010 01100011 1

  首先補一個“1”

  補位第二步:0110000101100010 01100011 10…..0

  然後補423個“0”

  我們可以把最後補位完成後的數據用16進制寫成下面的樣子
  

  61626380 0000000000000000 00000000

  00000000 0000000000000000 00000000

  00000000 0000000000000000 00000000

  00000000 00000000

  現在,數據的長度是448了,我們可以進行下一步操作。

  (二)補長度

  所謂的補長度是將原始數據的長度補到已經進行了補位操作的消息後面。通常用一個64位的數據來表示原始消息的長度。如果消息長度不大於2^64,那麽第一個字就是0。在進行了補長度的操作以後,整個消息就變成下面這樣了(16進制格式)
  

  61626380 0000000000000000 00000000
  00000000 0000000000000000 00000000

  00000000 0000000000000000 00000000

  00000000 0000000000000000 00000018

  (三)使用的常量

  在SHA256算法中,用到64個常量,這些常量是對自然數中前64個質數的立方根的小數部分取前32bit而來。這64個常量如下:

       428a2f98 71374491 b5c0fbcf e9b5dba5 
        3956c25b 59f111f1 923f82a4 ab1c5ed5 
        d807aa98 12835b01 243185be 550c7dc3 
        72be5d74 80deb1fe 9bdc06a7 c19bf174 
        e49b69c1 efbe4786 0fc19dc6 240ca1cc 
        2de92c6f 4a7484aa 5cb0a9dc 76f988da 
        983e5152 a831c66d b00327c8 bf597fc7 
        c6e00bf3 d5a79147 06ca6351 14292967 
        27b70a85 2e1b2138 4d2c6dfc 53380d13 
        650a7354 766a0abb 81c2c92e 92722c85 
        a2bfe8a1 a81a664b c24b8b70 c76c51a3 
        d192e819 d6990624 f40e3585 106aa070 
        19a4c116 1e376c08 2748774c 34b0bcb5  
        391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3 
        748f82ee 78a5636f 84c87814 8cc70208 
        90befffa a4506ceb bef9a3f7 c67178f2

  該算法使用了六種基本邏輯函數,由64 步叠代運算組成。每步都以256-bit 緩存值ABCDEFGH 為輸入,然後更新緩存內容。
  每步使用一個32bit 常數值Kt 和一個32bit Wt。

  (四)六種基本邏輯函數

        CH(x, y, z) = (x AND y) XOR ( (NOT x) AND z)  
        MAJ( x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)  
        BSIG0(x) = ROTR^2(x) XOR ROTR^13(x) XOR ROTR^22(x)  
        BSIG1(x) = ROTR^6(x) XOR ROTR^11(x) XOR ROTR^25(x)  
        SSIG0(x) = ROTR^7(x) XOR ROTR^18(x) XOR SHR^3(x)  
        SSIG1(x) = ROTR^17(x) XOR ROTR^19(x) XOR SHR^10(x) 

  其中 x、y、z皆為32bit的字。
  ROTR^2(x)是對x進行循環右移2位。

  運算邏輯,如圖所示:

技術分享圖片

技術分享圖片

技術分享圖片

  (五)計算消息摘要

  基本思想:就是將消息分成N個512bit的數據塊,哈希初值H(0)經過第一個數據塊得到H(1),H(1)經過第二個數據塊得到H(2),……,依次處理,最後得到H(N),然後將H(N)的8個32bit連接成256bit消息摘要。

  I、哈希初值H(0)

  SHA256算法中用到的哈希初值H(0)如下

     H(0)0 = 6a09e667 
        H(0)1 = bb67ae85  
        H(0)2 = 3c6ef372 
        H(0)3 = a54ff53a 
        H(0)4 = 510e527f 
        H(0)5 = 9b05688c 
        H(0)6 = 1f83d9ab 
        H(0)7 = 5be0cd19

  註:這些初值是對自然數中前8個質數3、5、7、11等的平方根的小數部分取前32bit而來。

II、 計算過程中用到的三種中間值

    1、64個32bit字的message schedule標記為w0、w1、…、w63。
    2、8個32bit字的工作變量標記為a、b、c、d、e、f、g。
    3、包括8個32bit字的哈希值標記為H(i)0、…、H(i)7

III、 工作流程

  原始消息分為N個512bit的消息塊。每個消息塊分成16個32bit的字標記為M(i)0、M(i)1、M(i)2、…、M(i)15然後對這N個消息塊依次進行如下處理

            For i=1 to N
        1)   For t = 0 to 15 
                     Wt = M(i)t 
                 For t = 16 to 63 

                     Wt = SSIG1(W(t-2)) + W(t-7) + SSIG0(t-15) + W(t-16) 
         2)  a = H(i-1)0 
                b = H(i-1)1 
                c = H(i-1)2 
                d = H(i-1)3 
                e = H(i-1)4 
                f = H(i-1)5 
                g = H(i-1)6 
                h = H(i-1)7
         3)For t = 0 to 63 
                    T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt 
                    T2 = BSIG0(a) + MAJ(a,b,c) 
                    h = g
                    g = f 
                    f = e 
                    e = d + T1 
                    d = c 
                    c = b 
                    b = a 
                    a = T1 + T2

           4)H(i)0 = a + H(i-1)0 
                 H(i)1 = b + H(i-1)1 
                 H(i)2 = c + H(i-1)2 
                 H(i)3 = d + H(i-1)3 
                 H(i)4 = e + H(i-1)4 
                 H(i)5 = f + H(i-1)5  
                 H(i)6 = g + H(i-1)6 
                 H(i)7 = h + H(i-1)7

  對N個消息塊依次進行以上四步操作後將最後得到的H(N)0、H(N)1、H(N)2、…、H(N)7串聯起來即可得到最後的256bit消息摘要。

代碼實現

I 調用庫函數:

  下面的示例計算 data 的SHA256哈希值,並將它存儲在 result 中。此示例假定存在一個預定義的常數 DATA_SIZE:

  C#的代碼示例:
1 byte[] result;
2 byte[] data = new byte[DATA_SIZE];
3 SHA256 shaM = new SHA256Managed();
4 result  = shaM.ComputeHash(data);
  Java的代碼示例:
1 ubyteresult[];
2 ubyte data[] = new ubyte[DATA_SIZE];
3 SHA256 shaM  = new SHA256Managed();
4 result  = shaM.ComputeHash(data);
  SQL的代碼示例:
1 SELECT sha2(data,256);
  PHP的代碼示例:
1 $result=hash(‘sha256‘, $data);

II 自己編寫代碼實現

  前面我們已經說明了SHA-256的計算過程,接下來我們將這一過程代碼化。同樣的首先定義一個上下文的結構。

技術分享圖片
 1 /** 定義SHA-256哈希操作的內容信息結構體 */
 2 typedef struct SHA256Context {
 3   uint32_t Intermediate_Hash[SHA256HashSize/4]; /* 信息摘要 */
 4   uint32_t Length_High;                         /* 按位計算的信息長度高字 */
 5   uint32_t Length_Low;                          /* 按位計算的信息長度低字 */
 6   int_least16_t Message_Block_Index;            /* 信息分組數組的索引 */
 7   uint8_t Message_Block[SHA256_Message_Block_Size];/* 512位信息分組 */
 8   int Computed;                                 /* 摘要計算標識 */
 9   int Corrupted;                                /* 信息摘要損壞標識 */
10 } SHA256Context;
技術分享圖片

  實現SHA256Context結構的初始化,為後續的計算過程做準備。

技術分享圖片
 1 static SHAStatusCode SHA224_256Reset(SHA256Context *context, uint32_t *H0)
 2 {
 3   if (!context) return shaNull;
 4   context->Length_High = context->Length_Low = 0;
 5   context->Message_Block_Index = 0;
 6   context->Intermediate_Hash[0] = H0[0];
 7   context->Intermediate_Hash[1] = H0[1];
 8   context->Intermediate_Hash[2] = H0[2];
 9   context->Intermediate_Hash[3] = H0[3];
10   context->Intermediate_Hash[4] = H0[4];
11   context->Intermediate_Hash[5] = H0[5];
12   context->Intermediate_Hash[6] = H0[6];
13   context->Intermediate_Hash[7] = H0[7];
14   context->Computed = 0;
15   context->Corrupted = shaSuccess;
16   return shaSuccess;
17 }
技術分享圖片

  接下來實現信息分組的輸入,這個函數接受一個字節數組作為下一個消息分組以便進行處理。

技術分享圖片
 1 SHAStatusCode SHA256Input(SHA256Context *context, const uint8_t *message_array,unsigned int length)
 2 {
 3   if (!context) return shaNull;
 4   if (!length) return shaSuccess;
 5   if (!message_array) return shaNull;
 6   if (context->Computed) return context->Corrupted = shaStateError;
 7   if (context->Corrupted) return context->Corrupted;
 8   while (length--)
 9   {
10     context->Message_Block[context->Message_Block_Index++] =*message_array;
11     if ((SHA224_256AddLength(context, 8) == shaSuccess) &&(context->Message_Block_Index == SHA256_Message_Block_Size))
12       SHA224_256ProcessMessageBlock(context);
13     message_array++;
14   }
15   return context->Corrupted;
16 }
技術分享圖片

  當然還需要一個消息處理及最終摘要輸出的函數,這個函數將返回一個224位或者256位的信息摘要到調用者給定的Message_Digest數組。返回的信息摘要,第一個元素索引為0,最後一個元素索引為27(SHA-2244)或者31(SHA-256)。

技術分享圖片
 1 static SHAStatusCode SHA224_256ResultN(SHA256Context *context,uint8_t Message_Digest[ ], int HashSize)
 2 {
 3   int i;
 4   if (!context) return shaNull;
 5   if (!Message_Digest) return shaNull;
 6   if (context->Corrupted) return context->Corrupted;
 7   if (!context->Computed)
 8     SHA224_256Finalize(context, 0x80);
 9   for (i = 0; i < HashSize; ++i)
10     Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
11   return shaSuccess;
12 }
技術分享圖片


區塊鏈中的哈希指針鏈

  哈希指針是一類數據結構,除了包含通常的指針外,還包含一些數據信息以及與這些信息相關的密碼哈希值,這就使得正常的指針可用於取回信息,哈希指針用於驗證信息是否發生改變。區塊鏈就可以看作一類使用哈希指針的鏈表,如下圖所示。這個鏈表鏈接一系列的區塊,每個區塊包含數據以及指向表中前一個區塊的指針。區塊鏈中,前一個區塊指針由哈希指針所替換,因此每個區塊不僅僅告訴前一個區塊的位置,也提供一個哈希值去驗證這個區塊所包含的數據是否發生改變。

技術分享圖片

哈希指針鏈

  可以利用區塊鏈去構造一個防篡改的日誌系統。在這個系統中,基於區塊鏈的日誌節點鏈表被用來存儲數據,鏈表節點通過哈希指針鏈接,新節點追加在日誌鏈表的尾部。同時,日誌鏈表的頭哈希指針所指向的頭節點內容不可改變。若日誌鏈表中的某個節點的數據被篡改,則系統能夠檢測出來。

  假定攻擊者改變了節點k的數據,由於其後繼節點k+1存儲了節點k的哈希值,由於密碼哈希函數的抗碰撞性,通過簡單地計算節點k的數據的哈希值,就能發現計算出的值與節點k+1的哈希指針值不一致,於是可以斷定節點k或節點k+1的信息被篡改。當然,攻擊者可能能夠連續改變前一個節點的哈希值來掩蓋不同,但這個策略在處理日誌鏈表的頭節點時將會失敗。特別地,一旦將鏈表頭部的哈希指針存儲在不能改變的地方,攻擊者將不能改變任何節點而不被發覺。

  因此,若攻擊者想在日誌鏈表中的任意位置改變數據,為保持一致性,他必須向表頭方向修改所有的哈希指針,最終由於不能改變鏈表頭部而失敗。因此,只需單個哈希指針,基本上就能保證整個鏈表的哈希值的一致性,從而達到防篡改的目的。


        哈哈哈哈哈哈,區塊鏈中加密算法——Hash算法之SHA256算法 到這裏就更新完了!

             下一節給大家講Merkle樹敬請期待·····

Reference:

  1.SHA256代碼實現:https://www.cnblogs.com/foxclever/p/8370712.html

  2.SHA256算法介紹:https://blog.csdn.net/wowotuo/article/details/78907380

  3.《區塊鏈技術指南》鄒均,張海寧,唐屹,李磊 著

1.3.1 區塊鏈中的加密算法——Hash算法(更新)