數字簽名的生成
假設Alice要給Bob發一個經過數字簽名的消息,他們首先需要定義一組共同接受的橢圓曲線加密用參數,簡單的,這組參數可表示爲 (CURVE, G, n)
其中,CURVE表示橢圓曲線點域和幾何方程;G是所有點倍積運算的基點;n是該橢圓曲線的可倍積階數(multiplicative order),作爲一個很大的質數,n的幾何意義在於,nG = 0,即點倍積nG的結果不存在,而對於小於n的任何一個正整數 m = [1,n-1],點倍積mG都可以得到一個合理的處於該橢圓曲線上的點。
其次,Alice要創建一對鑰,即一個私鑰和一個公鑰。私鑰來自於[1, n-1]範圍內一個隨機數:dA = rand(1, n-1)
公鑰如下,它來自私鑰和基點的橢圓曲線點倍積:QA = dA X G
Alice想要對消息m作數字簽名,有以下步驟:
- 計算
e = HASH(m)
,HASH是一個哈希加密函數,比如SHA-2,或SHA-3。 - 計算
z
,來自e的二進制形式下最左邊(即最高位)L_n個bits,而L_n是上述橢圓曲線參數中的可倍積階數n的二進制長度。注意z 可能大於n,但長度絕對不會比 n 更長。 - 從 [1, n-1] 內,隨機選擇一個符合加密學隨機安全性的整數
k
。 - 計算一個橢圓曲線上點:
(x1, y1) = k X G
- 以下式計算 r 值, 如果r == 0, 則返回步驟3重新計算
r = x1 mod n
- 以下式計算 s 值,如果 s == 0,則返回步驟3重新計算
- 生成的數字簽名就是
(r, s)
Alice 用自己的私鑰和隨機數 k 簽名了哈希值 z。Bob 用 Alice 的公鑰來驗證簽名的正確性
特別需要注意的是步驟3中 k 的選擇,它不僅要滿足加密學的隨機安全性要求,要像私鑰一樣保護起來,更重要的是,在每次生成一個新的數字簽名時,這個 k 必須每次都要更新。否則,通過上述數字簽名過程中的算式相互換算,很容易從中破譯出私鑰!具體換算過程可見wiki_ECDSA。
ECDSA簽名可能泄漏私鑰的另一種方式是 {\ displaystyle k}ķ是由錯誤的隨機數發生器產生的。這樣的隨機數生成失敗導致Android比特幣錢包的用戶在2013年8月損失了資金
數字簽名的驗證
對於消息的接收方Bob來說,他除了收到數字簽名文件外,還會有一份公鑰。所以Bob的驗證分兩部分,首先驗證公鑰,然後驗證簽名文件(r, s)。
公鑰的驗證
- 公鑰
QA
的座標應是有效的,不會等於一個極限值空點O
- 通過公鑰
QA
的座標驗證它必須是處於該橢圓曲線上的點。 - 應有下式成立,即曲線的可倍積階數 n 與公鑰的點倍積不存在
簽名文件的驗證
- 驗證 r 和 s 均是處於[1, n-1]範圍內的整型數;否則驗證失敗
- 計算
e = HASH(m)
,HASH()即簽名生成過程步驟1中使用的哈希函數。 - 計算
z
,來自 e的最左邊L_n個bits - 計算兩個參數
u1
和u2
:
- 計算(x1, y1),如果(x1, y1)不是一個橢圓曲線上的點,則驗證失敗:
- 如果下面等式成立, 則簽名有效
公鑰恢復
收到消息m
和愛麗絲的簽名r,s
,在該消息上,Bob可以(可能)恢復Alice的公鑰:
- 驗證
r
和s
是整數[1,n-1]
。如果不是,則簽名無效。 - 計算曲線點
R=(x1, y1)
,x1
是其中之一 r, r+n, r+2n等(提供的x1
對於字段元素來說不是太大), y1是是滿足曲線方程式的值。
請注意,可能有幾個滿足這些條件的曲線點,每個曲線點都不同R
值將產生一個不同的已恢復密鑰。 - 計算
e = HASH(m)
,HASH()即簽名生成過程步驟1中使用的哈希函數。 - 計算
z
,來自 e的最左邊L_n個bits - 計算兩個參數
u1
和u2
:
- 計算曲線點
- 如果QA匹配Alice的公鑰, 則簽名有效
- 如果嘗試了所有可能的R點且沒有匹配Alice的公鑰,則簽名無效。
請注意,無效的簽名或來自其他消息的簽名將導致恢復不正確的公鑰。如果事先知道簽名者的公鑰(或其哈希),則恢復算法只能用於檢查簽名的有效性。
公式推導請參考: wiki_ECDSA
公鏈簽名與驗籤算法
摘要生成 | 簽名算法 | 簽名數據格式 | 驗籤算法 | |
---|---|---|---|---|
BTC | SHA256 | ECDSA-secp256k1 | BIP66之後採用DER編碼. 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] |
verify模式 OP_CHECKSIG ECDSA_CheckSignature (pubKeyStr,sigStr, sha256(sha256(verifyThisStr))) |
ETH | SHA3-Keccack | ECDSA-secp256k1 | (R,S,V) V是recid, 爲0或者1, v := sig[0] - 27 |
recove模式pub, err := crypto.Ecrecover(sighash[:], sig) |
EOS | SHA256 | ECDSA-secp256k1|r1 | (V,R,S) V中帶了recid v: 27 + 4 + recid , 從簽名中提取出recove id: V - 4 - 27 |
recove模式recov = public_key_type( sig, digest ) |
公鏈 ECDSA 驗籤方式
用公鑰去verify的方式:
-
BTC :
ECDSA_CheckSignature(pubKeyStr,sigStr,sha256(sha256(verifyThisStr)))
(參考資料: https://en.bitcoin.it/wiki/File:Bitcoin_OpCheckSig_InDetail.png )
-
Hyperledger Fabric
valid, err := id.msp.bccsp.Verify([id.pk](http://id.pk/), sig, digest, nil)
(參考資料: https://blog.csdn.net/idsuf698987/article/details/81677133 )
recove出公鑰的方式:
- ETH
pub, err := crypto.Ecrecover(sighash[:], sig) //摘自源碼
- EOS
recov = public_key_type( sig, digest ) //摘自源碼