比特幣原始碼解讀之私鑰、公鑰和地址
阿新 • • 發佈:2019-01-09
(本文使用的是比特幣v0.1.0版本 點選下載原始碼)
比特幣是建立在數字加密基礎上的,接觸過比特幣的朋友應該知道:
(1)購買比特幣最後是通過一個比特幣地址進行的,比特幣地址就像支票中的支付物件(收款方);
(2)而比特幣地址則是通過公鑰單向雜湊生成的;
(3)而公鑰則是通過私鑰使用橢圓曲線演算法生成的,
(4)而私鑰通過作業系統底層生成的256位隨機熵;
比特幣系統的私鑰、公鑰和地址生成是通過OpenSSL庫實現的。
具體流程圖如下所示:
公鑰和私鑰的生成
金鑰的生成
CKey key;
key.MakeNewKey();
voidMakeNewKey()
{
if(!EC_KEY_generate_key(pkey))
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
}
公鑰的獲取
vector<unsignedchar>GetPubKey()const
{
unsignedint nSize = i2o_ECPublicKey(pkey, NULL);
if(!nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
vector<unsignedchar> vchPubKey(nSize,0);
unsignedchar* pbegin
if(i2o_ECPublicKey(pkey,&pbegin)!= nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
return vchPubKey;
}
私鑰的獲取
CPrivKeyGetPrivKey()const
{
unsignedint nSize = i2d_ECPrivateKey(pkey, NULL);
if(!nSize)
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"
CPrivKey vchPrivKey(nSize,0);
unsignedchar* pbegin =&vchPrivKey[0];
if(i2d_ECPrivateKey(pkey,&pbegin)!= nSize)
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
return vchPrivKey;
}
公鑰和私鑰的儲存
私鑰儲存在mapKeys結構中(鍵為公鑰),公鑰儲存在mapPubKeys結果中(鍵為公鑰HASH)
mapKeys[key.GetPubKey()]= key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())]= key.GetPubKey();
通過公鑰生成公鑰HASH
公鑰先使用SHA256函式再使用RIPEMD160函式生成公鑰HASH
inlineuint160Hash160(constvector<unsignedchar>& vch)
{
uint256 hash1;
SHA256(&vch[0], vch.size(),(unsignedchar*)&hash1);
uint160 hash2;
RIPEMD160((unsignedchar*)&hash1,sizeof(hash1),(unsignedchar*)&hash2);
return hash2;
}
通過公鑰Hash生成地址
公鑰HASH字首加上一個位元組的版本號
inline string Hash160ToAddress(uint160 hash160)
{
// add 1-byte version number to the front
vector<unsignedchar> vch(1, ADDRESSVERSION);
vch.insert(vch.end(), UBEGIN(hash160), UEND(hash160));
returnEncodeBase58Check(vch);
}
公鑰HASH字尾加入4位元組的校驗碼
inline string EncodeBase58Check(constvector<unsignedchar>& vchIn)
{
// add 4-byte hash check to the end
vector<unsignedchar> vch(vchIn);
uint256 hash =Hash(vch.begin(), vch.end());
vch.insert(vch.end(),(unsignedchar*)&hash,(unsignedchar*)&hash +4);
returnEncodeBase58(vch);
}
通過EncodeBase58編碼生成比特幣地址
inline string EncodeBase58(constvector<unsignedchar>& vch)
{
returnEncodeBase58(&vch[0],&vch[0]+ vch.size());
}
作者:雨後的蚊子