pybitcointools源碼分析之RFC6979

在分析源碼之前,一定要先講講什么是RFC6979。

比特幣的簽名機制是基于橢圓曲線算法。在橢圓曲線里面k值(用于簽名)是要嚴格保密的,暴露k值就相當于暴露私鑰。k值要保證兩點:

  1. 保密
  2. 唯一

有人提出一種方式來產生k值,類似下面這樣的公式:

k = SHA256(d + HASH(m));

其中,d是私鑰,m是消息,我們一般會對消息的HASH進行簽名,因此這里是HASH(m)。

有私鑰d,就保證了“保密”,再加上消息m,保證了“唯一”,這也是“確定性”的算法,只要SHA256是安全的,此算法就是安全的。

當然真正的RFC6979比這個要復雜的多。

k在使用橢圓曲線簽名的參與過程

關于橢圓曲線算法的詳細信息請自行查閱

這里只簡要說明k在使用橢圓曲線簽名的參與過程。

簽名的步驟:

  1. 使用bits2int將H(m)變換成模q的整數
h = bits2int(H(m))mod q
  1. 產生一個隨機值q,稱為k。值不得為0;它在[1,q-1]范圍內。大多數
    在傳統的ECDSA中,通過在q-1范圍內選擇一個隨機值作為k。
  1. k和其它關鍵參數計算值r(模q):

對于ECDSA(橢圓曲線):計算點kG;其X坐標(a被定義為E的字段的成員)被轉換為一個整數,其被減數為q,產生r。

如果r為零,則應選擇一個新的k再次計算(這是一個完全不可能發生的事情)。

計算值s(模q):

s =(h + x * r)/ k mod q

(r,s)即使是簽名。

RFC6979(確定性簽名算法)生產k的流程

首先我們定義:

    HMAC_K(V)

使用密鑰(key)K對數據V進行HMAC算法。

給定輸入消息m,應用以下過程:

  1. 通過哈希函數H處理m,產生:
h1 = H(m)
V = 0x01 0x01 0x01 ... 0x01

V(以比特)的長度等于8 * ceil(hlen / 8)。例如,如果H是SHA-256,則V被設置為值為1的32個八位字節的序列。

K = 0x00 0x00 0x00 ... 0x00

K的長度(以比特)等于8 * ceil(hlen / 8)。

K = HMAC_K(V || 0x00 || int2octets(x)|| bits2octets(h1))

'||'表示連接。x是私鑰。

V = HMAC_K(V)
K = HMAC_K(V || 0x01 || int2octets(x)|| bits2octets(h1))
V = HMAC_K(V)
  1. 執行以下流程,直到找到適當的值k:
  • 將T設置為空序列。 T的長度(以比特為單位)表示為tlen, 因此tlen = 0。

  • 當tlen <qlen時,請執行以下操作:

V = HMAC_K(V)
T = T || V

  • 計算
k = bits2int(T)

如果k的值在[1,q-1]范圍內,那么k的生成就完了。否則,計算:

K = HMAC_K(V || 0x00)
V = HMAC_K(V)

并循環(嘗試生成一個新的T,等等)。

源碼分析

有了上面的理論支撐再來分析源碼就比較容易了。

i = 1
result_k = deterministic_generate_k(bin_sha256(str(i)), encode(i, 256, 32))
print result_k

bin_sha256()返回輸入數據的hash256的結果,不過是python的byte格式的(也就是字符串在計算機的真正樣子)。比如這里的

bin_sha256('1')

#結果是:

b'\x6b\x86\xb2\x73\xff\x34\xfc\xe1\x9d\x6b\x80\x4e\xff\x5a\x3f\x57\x47\xad\xa4\xea\xa2\x2f\x1d\x49\xc0\x1e\x52\xdd\xb7\x87\x5b\x4b'

這里的結果作為消息的hash結果,也就是上面提到的h1。

encode(i, 256, 32)得到一個私鑰。

下面進入deterministic_generate_k里面看看,

def deterministic_generate_k(msghash, priv):
    v = b'\x01' * 32
    k = b'\x00' * 32

    priv = encode_privkey(priv, 'bin')

    msghash = encode(hash_to_int(msghash), 256, 32)

    k = hmac.new(k, v+b'\x00'+priv+msghash, hashlib.sha256).digest()
    v = hmac.new(k, v, hashlib.sha256).digest()
    k = hmac.new(k, v+b'\x01'+priv+msghash, hashlib.sha256).digest()
    v = hmac.new(k, v, hashlib.sha256).digest()
    return decode(hmac.new(k, v, hashlib.sha256).digest(), 256)
v = b'\x01' * 32
k = b'\x00' * 32

分別代表上面流程中的

V = 0x01 0x01 0x01 ... 0x01

K = 0x00 0x00 0x00 ... 0x00

encode(hash_to_int(msghash), 256, 32)對應bits2octets(h1)。

接下來的5行,就是進行上面的4~8的步驟。

參考

[1] http://www.8btc.com/rfc6979

[2] https://tools.ietf.org/html/rfc6979

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容