在分析源碼之前柱查,一定要先講講什么是RFC6979辨液。
比特幣的簽名機(jī)制是基于橢圓曲線算法。在橢圓曲線里面k值(用于簽名)是要嚴(yán)格保密的蝠筑,暴露k值就相當(dāng)于暴露私鑰狞膘。k值要保證兩點(diǎn):
- 保密
- 唯一
有人提出一種方式來產(chǎn)生k值,類似下面這樣的公式:
k = SHA256(d + HASH(m));
其中菱肖,d是私鑰客冈,m是消息,我們一般會對消息的HASH進(jìn)行簽名稳强,因此這里是HASH(m)。
有私鑰d和悦,就保證了“保密”退疫,再加上消息m,保證了“唯一”鸽素,這也是“確定性”的算法褒繁,只要SHA256是安全的,此算法就是安全的馍忽。
當(dāng)然真正的RFC6979比這個要復(fù)雜的多棒坏。
k在使用橢圓曲線簽名的參與過程
關(guān)于橢圓曲線算法的詳細(xì)信息請自行查閱
這里只簡要說明k在使用橢圓曲線簽名的參與過程。
簽名的步驟:
- 使用bits2int將H(m)變換成模q的整數(shù)
h = bits2int(H(m))mod q
- 產(chǎn)生一個隨機(jī)值q遭笋,稱為k坝冕。值不得為0;它在[1,q-1]范圍內(nèi)瓦呼。大多數(shù)
在傳統(tǒng)的ECDSA中喂窟,通過在q-1范圍內(nèi)選擇一個隨機(jī)值作為k。
- k和其它關(guān)鍵參數(shù)計算值r(模q):
對于ECDSA(橢圓曲線):計算點(diǎn)kG;其X坐標(biāo)(a被定義為E的字段的成員)被轉(zhuǎn)換為一個整數(shù),其被減數(shù)為q磨澡,產(chǎn)生r碗啄。
如果r為零,則應(yīng)選擇一個新的k再次計算(這是一個完全不可能發(fā)生的事情)稳摄。
計算值s(模q):
s =(h + x * r)/ k mod q
(r稚字,s)即使是簽名。
RFC6979(確定性簽名算法)生產(chǎn)k的流程
首先我們定義:
HMAC_K(V)
使用密鑰(key)K對數(shù)據(jù)V進(jìn)行HMAC算法厦酬。
給定輸入消息m胆描,應(yīng)用以下過程:
- 通過哈希函數(shù)H處理m,產(chǎn)生:
h1 = H(m)
V = 0x01 0x01 0x01 ... 0x01
V(以比特)的長度等于8 * ceil(hlen / 8)弃锐。例如袄友,如果H是SHA-256,則V被設(shè)置為值為1的32個八位字節(jié)的序列霹菊。
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)
- 執(zhí)行以下流程鸠按,直到找到適當(dāng)?shù)闹祂:
將T設(shè)置為空序列。 T的長度(以比特為單位)表示為tlen, 因此tlen = 0饶碘。
當(dāng)tlen <qlen時目尖,請執(zhí)行以下操作:
V = HMAC_K(V)
T = T || V
- 計算
k = bits2int(T)
如果k的值在[1,q-1]范圍內(nèi)扎运,那么k的生成就完了瑟曲。否則,計算:
K = HMAC_K(V || 0x00)
V = HMAC_K(V)
并循環(huán)(嘗試生成一個新的T豪治,等等)洞拨。
源碼分析
有了上面的理論支撐再來分析源碼就比較容易了。
i = 1
result_k = deterministic_generate_k(bin_sha256(str(i)), encode(i, 256, 32))
print result_k
bin_sha256()返回輸入數(shù)據(jù)的hash256的結(jié)果负拟,不過是python的byte格式的(也就是字符串在計算機(jī)的真正樣子)烦衣。比如這里的
bin_sha256('1')
#結(jié)果是:
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'
這里的結(jié)果作為消息的hash結(jié)果,也就是上面提到的h1掩浙。
encode(i, 256, 32)得到一個私鑰花吟。
下面進(jìn)入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)對應(yīng)bits2octets(h1)厨姚。
接下來的5行衅澈,就是進(jìn)行上面的4~8的步驟。
參考