僞代碼簡述 ECDSA 簽名過程 | 聯盟鏈開發(十一)
程序員易懂的 ECDSA 原理簡述
在《比特幣極速入門指南》一書裏,我闡述了公私鑰究竟是什麼:
- 私鑰的本質: 私鑰的本質是一個數字,這個數字用 16 進製表示的話,長度是 64;轉換爲字節,是 32 字節。
- 公鑰的本質: 用私鑰生成Secp256k1曲線上的一個點,將 x 與 y 拼接起來,再在開頭加上 <<04>> 後得到一個數字,這個數字就是公鑰。用 16進製表示的話,長度是 130;轉換爲字節,是 65 字節。
地址:
閱讀版—— http://dwz.date/a8dY
互動版 —— https://xue.cn/hub/app/books/3
由於是「入門指南」,所以沒有對 ECDSA 具體的簽名過程進行詳細闡述,只做黑箱處理。但是,對於進階讀者而言,瞭解 ECDSA 簽名的實現邏輯還是有其必要的。
在一般介紹 ECDSA 原理的文章中,普遍使用數學語言。雖然非常嚴謹,但讀起來還是比較費勁。所以,今天我在這裏,通過僞代碼的形式,介紹 ECDSA 的原理,以便大家更好的理解。
首先我們定義這件事兒裏有幾個角色:
-
私鑰小姐與公鑰先生
我們稱其爲 priv 與 pub。
-
要加密的信息 m
在區塊鏈裏一般 m = 交易,不過理論上只要是個東西就能加密。
-
G 點
G.x0x79……98
G.y0x48……B8
G.order0xFF……41
具體的數值我們可以從網上搜到,但在這裏我們不用管它,只要知道 G 點有三個參數:x, y, order 就行了!
接着我們定義兩個操作:
-
Point.mult(num, Point)
點的乘法,參數是一個數字與一個 (x, y) 點,結果是一個點。我們可以把這個操作看做黑箱,而不用去深究這個操作究竟做了些啥。
-
calculate_rem(num1, num2)
取餘操作
-
hash_and_sth(m)
我們對信息 m 做一些處理,具體咋處理的不用管,結果就是我們能拿 m 驗證出來出來的內容是否正確,但不能拿處理出來的內容反推 m —— 傳說中的 hash 函數。
我們現在來用僞代碼愉快地生成數字簽名吧!
數字簽名生成過程
- gen_k()
我們首先用 gen_k() 函數生成一個取值範圍爲[1, order-1] 的隨機數,稱之爲 k。
- Point.mult(k, G)
Point.mult(k, G) = Q_point = (x, y)。
-
calculate_rem(x, order)
calculate_rem(x, order) = r,如果 r 爲 0,則回到第一步,重新生成 k。
-
calculate_s(k, hash_and_sth(m), priv)
calculate_s(k, hash_and_sth(m), priv) = s,如果 s 爲 0,再次重新生成 k。
-
v = 27 + calculate_rem(y, 2)
有了 v,我們驗籤就更快了,不然要遍歷好幾個點去找哪一個點是對的。具體怎麼做的可以暫且不理,有興趣的話看:
http://www.secg.org/sec1-v2.pdf
-
r & s & v = signature
把三個東西連起來,得到數字簽名!
和比特幣存在差異,比特幣在 ECDSA 簽名後採用了 DER 編碼模式,所以比特幣的簽名長度是不定的,在71 - 73 個字節之前。但是以太坊則使用的標準 ECDSA 流程,所以簽名固定爲 r(35字節)+ s(35字節)+v (1字節)=71字節。
此處 1 字節爲 8 個二進制位,即 2 個十六進制位,即 0x00 - 0xFF,用十進制表示則是 0 - 255。
此外,由於簽名中存在隨機數 k,所以對同一信息用同一私鑰,每次簽出來的簽名也是不一樣的!
把上述過程用僞代碼表示,則是:
@spec gen_sig(byte32, string) return byte71 def gen_sig(priv, m) do q_point= gen_k() |> Point.mult(G) r = calculate_rem(q_point, G.order) s = calculate_s(k, hash_and_sth(m), priv) v = 27 + calculate_rem(q_point.y, 2) return r & s & v end
數字簽名驗簽過程……嗯,明日再談吧(懶~
在《比特幣極速入門指南》一書裏,我闡述了公私鑰究竟是什麼:
- 私鑰的本質: 私鑰的本質是一個數字,這個數字用 16 進製表示的話,長度是 64;轉換爲字節,是 32 字節。
- 公鑰的本質: 用私鑰生成Secp256k1曲線上的一個點,將 x 與 y 拼接起來,再在開頭加上 <<04>> 後得到一個數字,這個數字就是公鑰。用 16進製表示的話,長度是 130;轉換爲字節,是 65 字節。
地址:
閱讀版—— http://dwz.date/a8dY
互動版 —— https://xue.cn/hub/app/books/3
由於是「入門指南」,所以沒有對 ECDSA 具體的簽名過程進行詳細闡述,只做黑箱處理。但是,對於進階讀者而言,瞭解 ECDSA 簽名的實現邏輯還是有其必要的。
在一般介紹 ECDSA 原理的文章中,普遍使用數學語言。雖然非常嚴謹,但讀起來還是比較費勁。所以,今天我在這裏,通過僞代碼的形式,介紹 ECDSA 的原理,以便大家更好的理解。
首先我們定義這件事兒裏有幾個角色:
-
私鑰小姐與公鑰先生
我們稱其爲 priv 與 pub。
-
要加密的信息 m
在區塊鏈裏一般 m = 交易,不過理論上只要是個東西就能加密。
-
G 點
G.x0x79……98
G.y0x48……B8
G.order0xFF……41
具體的數值我們可以從網上搜到,但在這裏我們不用管它,只要知道 G 點有三個參數:x, y, order 就行了!
接着我們定義兩個操作:
-
Point.mult(num, Point)
點的乘法,參數是一個數字與一個 (x, y) 點,結果是一個點。我們可以把這個操作看做黑箱,而不用去深究這個操作究竟做了些啥。
-
calculate_rem(num1, num2)
取餘操作
-
hash_and_sth(m)
我們對信息 m 做一些處理,具體咋處理的不用管,結果就是我們能拿 m 驗證出來出來的內容是否正確,但不能拿處理出來的內容反推 m —— 傳說中的 hash 函數。
我們現在來用僞代碼愉快地生成數字簽名吧!
數字簽名生成過程
- gen_k()
我們首先用 gen_k() 函數生成一個取值範圍爲[1, order-1] 的隨機數,稱之爲 k。
- Point.mult(k, G)
Point.mult(k, G) = Q_point = (x, y)。
-
calculate_rem(x, order)
calculate_rem(x, order) = r,如果 r 爲 0,則回到第一步,重新生成 k。
-
calculate_s(k, hash_and_sth(m), priv)
calculate_s(k, hash_and_sth(m), priv) = s,如果 s 爲 0,再次重新生成 k。
-
v = 27 + calculate_rem(y, 2)
有了 v,我們驗籤就更快了,不然要遍歷好幾個點去找哪一個點是對的。具體怎麼做的可以暫且不理,有興趣的話看:
-
r & s & v = signature
把三個東西連起來,得到數字簽名!
和比特幣存在差異,比特幣在 ECDSA 簽名後採用了 DER 編碼模式,所以比特幣的簽名長度是不定的,在71 - 73 個字節之前。但是以太坊則使用的標準 ECDSA 流程,所以簽名固定爲 r(35字節)+ s(35字節)+v (1字節)=71字節。
此處 1 字節爲 8 個二進制位,即 2 個十六進制位,即 0x00 - 0xFF,用十進制表示則是 0 - 255。
此外,由於簽名中存在隨機數 k,所以對同一信息用同一私鑰,每次簽出來的簽名也是不一樣的!
把上述過程用僞代碼表示,則是:
@spec gen_sig(byte32, string) return byte71 def gen_sig(priv, m) do q_point= gen_k() |> Point.mult(G) r = calculate_rem(q_point, G.order) s = calculate_s(k, hash_and_sth(m), priv) v = 27 + calculate_rem(q_point.y, 2) return r & s & v end
數字簽名驗簽過程……嗯,明日再談吧(懶~
本文參與登鏈社區寫作激勵計劃 ,好文好收益,歡迎正在閱讀的你也加入。
- 發表於 28分鐘前
- 閱讀 ( 9 )
- 學分 ( 5 )
- 分類:FISCO BCOS