數字簽名是密碼學領域的第二個非常重要的概念,第一個是 hash 算法,前面我們已經花了兩篇文章做了瞭解,見 密碼學之 Hash 算法 和 Hash 指針和數據結構(區塊鏈和默克爾樹),其在互聯網安全領域以及區塊鏈系統中都有着非常重要的應用。
可以把數字簽名看成傳統簽名在數字領域的一個延伸,特徵如下:
-
簽名不可以僞造,但是可以被驗證
-
簽名和特定的文檔緊密相關
也就是說,雖然我們的簽名是以數字的形式表達的,但和傳統紙筆簽名一樣,筆跡不能被輕易的僞造,並且我們根據筆跡就可以知道是誰籤的。同時,人們也很難有方法將一處簽名嫁接到另外一處。
接着看一下數字簽名的 API 表達:
這裏有三個重要的操作:
-
生成祕鑰對
-
簽名
-
驗籤
第一步主要是利用一些工具生成公、私鑰,至於什麼是公鑰,什麼是私鑰,以及它們之間的關係,下一篇關於 PKI 體系的文章我們會有一個系統的認識。這裏只要明確,私鑰本質上就是一串隨機數,你可以通過擲骰子算出這段隨機數,但是更加保險的做法是通過一些成熟的庫工具。而公鑰是基於某種算法,通過私鑰推算出來的。
一般情況下,公鑰可以任意公佈,但是私鑰需要嚴加保管。私鑰用來對一段信息進行簽名。而公鑰可以驗證這段簽名的合法性以及身份(我們通常都會有 public keys as identities 的說法):
顯然,理論上簽名是不應該可以被僞造,否則我們做的所有工作都失去了意義。倘若有壞人鑽了空子非要去僞造簽名,會有成功的機會嗎?先看一下壞人掌握的信息:
-
公鑰
-
已經簽過名的信息
ok,爲了模擬這個場景,有人很無聊的發明了下面這個遊戲 …
假設圖中的 challenger 是我,那麼我在生成公鑰和私鑰之後,將公鑰公佈出去。那壞人,圖中的 attacker 就知曉了我的公鑰。同時,我不斷的給這個壞人發送附帶了我的數字簽名的信息,讓他分析直到他聲稱他已經通過所掌握的信息,模擬出了我的簽名,並將其發送給我驗證。
但理論上,無論我選擇的是什麼簽名算法,attacker 應該永遠不會模擬出我的簽名。
回到工業實現上,比特幣等區塊鏈系統通常使用橢圓曲線數字簽名算法標準是 ECDSA,其理論基礎是基於橢圓曲線離散對數問題的難解性,基本的簽名和驗簽過程如下:
簽名:
-
選擇一條橢圓曲線 Ep(a,b),和基點 G
-
選擇私有密鑰 k (k
- 產生一個隨機整數 r (r
-
將原數據和點 R 的座標值 x,y 作爲參數,計算 SHA1 做爲 hash,即 Hash=SHA1(原數據 ,x,y)
-
計算 s≡r – Hash * k (mod n)
-
r 和 s 做爲簽名值,如果 r 和 s 其中一個爲 0,重新從第 3 步開始執行
驗籤:
-
接受方在收到消息 (m) 和簽名值 (r,s) 後,進行以下運算
-
計算:sG+H(m)P=(x1,y1), r1≡ x1 mod p
-
驗證等式:r1 ≡ r mod p
各個主流語言都會有對 ECDSA 標準的實現,如 Golang 的包 crypto/ecdsa,Java 的 java.security 包。比特幣 btcd 和以太坊 geth 也有對應 secp256k1 標準和實現。
歡迎讀者加入哈希 1024 區塊鏈社區微信羣,進行更多的區塊鏈技術交流,可關注本公衆號,在後臺回覆“哈希”即可。