隨機性在簽名中的重要性
簽名生成算法使用隨機密鑰k
作爲短暫私鑰/公鑰對的基礎。k的值並不重要,只要它是隨機的。如果使用相同的值k在不同的消息(交易)上生成兩個簽名,那麼任何人都可以計算出簽名私鑰。在簽名算法中重用相同的k值的會導致私鑰的暴露!
如果在兩個不同的交易中,在簽名算法中使用相同的值k,則私鑰可以被計算並暴露給世界!
這不僅僅是一個理論上的可能性。我們已經看到比特幣中幾種不同實現的交易簽名算法因爲這個問題導致私人密鑰暴露。人們由於無意中重複使用k值而導致資金被竊取。重用k值的最常見原因是隨機數生成器未正確初始化。
爲了避免這個漏洞,業界最佳實踐不是用熵播種的隨機數生成器生成k值,而是使用交易數據本身播種的確定性隨機進程。這確保每個交易產生不同的k值。在互聯網工程任務組(InternetEngineering Task Force)發佈的RFC 6979中定義了k值的確定性初始化的行業標準算法。
如果你正在實現一種用於在區塊鏈中籤署交易的算法,則必須使用RFC 6979
或類似的確定性隨機算法
來確保爲每個交易生成不同的k值。
RFC 6979: 確定性隨機算法
確定性使用數字簽名算法(DSA)和 橢圓曲線數字簽名算法(ECDSA)
該標準定義了確定性的數字簽名生成過程: 此類簽名與標準數字簽名算法(DSA)和橢圓曲線數字簽名算法(ECDSA)數字簽名兼容,並且可以使用未經修改的驗證程序進行處理,這些驗證程序無需瞭解其中描述的過程。確定性簽名保留了與數字簽名相關聯的密碼安全性功能,但是由於它們不需要訪問高質量隨機性源,因此可以在各種環境中更輕鬆地實現。
- 簽署相同的交易將生成相同的k值
- 簽署不同的交易將生成不同的k值
// secp256k1庫中的用確定性隨機算法產生隨機數k的方法
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
secp256k1_rfc6979_hmac_sha256_t rng;
unsigned int i;
secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0);
for (i = 0; i <= counter; i++) {
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
}
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
return 1;
}
參考: RFC 6979