爲了爲保證存儲於區塊鏈中的信息的安全與完整,區塊鏈中使用了包含密碼哈希函數和橢圓曲線公鑰密碼技術在內的大量的現代密碼學技術,同時,這些密碼學技術也被用於設計基於工做量證實的共識算法並識別用戶。html
在前邊的文章中已經系統的講述了密碼學中的哈希算法,在本節,將會給你們介紹Hash算法在區塊鏈中的應用!算法
概念回顧:c#
哈希函數:是一類數學函數,能夠在有限合理的時間內,將任意長度的消息壓縮爲固定長度的二進制串,其輸出值稱爲哈希值,也稱爲散列值。數組
以哈希函數爲基礎構造的哈希算法,在現代密碼學中扮演着重要的角色,經常使用於實現數據完整性和實體認證,同時也構成多種密碼體制和協議的安全保障。緩存
碰撞是與哈希函數相關的重要概念,體現着哈希函數的安全性,所謂碰撞是指兩個不一樣的消息在同一個哈希函數做用下,具備相同的哈希值。安全
哈希函數的安全性是指在現有的計算資源(包括時間、空間、資金等)下,找到一個碰撞是不可行的。數據結構
區塊鏈中的加密算法······即將開始!函數
噔噔、噔···噔···!學習
比特幣中的加密算法:區塊鏈
在比特幣系統中使用了兩個密碼學Hash函數,一個是SHA256 和 RIPEMD160。
其中:RIPEMD160主要用於生成比特幣地址,咱們着重分析比特幣中用得最多的SHA256算法。
SHA歷史介紹: SHA256屬於著名的SHA家族一員。SHA(Secure Hash Algorithm,安全哈希算法)是一類由美國國家標準與技術研究院(NIST)發佈的密碼哈希函數。
正式名稱爲SHA的第一個成員發佈於1993年,兩年以後,著名的SHA-1發佈,以後另外的4種變體相繼發佈,包括SHA22四、SHA25六、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. 兩個不一樣的消息不會產生一樣的消息摘要。
1、術語和概念
(一)位(Bit),字節(Byte)和字(Word)
SHA始終把消息當成一個位(bit)字符串來處理。本文中,一個「字」(Word)是32位,而一個「字節」(Byte)是8位。好比,字符串「abc」能夠被轉換成一個位字符串:01100001 01100010 01100011。它也能夠被表示成16進制字符串:0x616263.
2、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個質數三、五、七、11等的平方根的小數部分取前32bit而來。
II、 計算過程當中用到的三種中間值
1、64個32bit字的message schedule標記爲w0、w一、…、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)一、M(i)二、…、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)一、H(N)二、…、H(N)7串聯起來便可獲得最後的256bit消息摘要。
代碼實現
I 調用庫函數:
下面的示例計算 data 的SHA256哈希值,並將它存儲在 result 中。此示例假定存在一個預約義的常數 DATA_SIZE:
1 byte[] result; 2 byte[] data = new byte[DATA_SIZE]; 3 SHA256 shaM = new SHA256Managed(); 4 result = shaM.ComputeHash(data);
1 ubyteresult[]; 2 ubyte data[] = new ubyte[DATA_SIZE]; 3 SHA256 shaM = new SHA256Managed(); 4 result = shaM.ComputeHash(data);
1 SELECT sha2(data,256);
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樹,敬請期待·····
【時間倉促,若有錯誤,歡迎指正! || 歡迎留下您的評語! 你們一塊兒探討、學習區塊鏈!】
【轉載請註明出處!http://www.cnblogs.com/X-knight/】
Reference:
1.SHA256代碼實現:http://www.javashuo.com/article/p-rkhwanbk-ck.html
2.SHA256算法介紹:http://www.javashuo.com/article/p-yicjxzia-mk.html