3、區塊鏈之比特幣的私鑰、公鑰、地址
阿新 • • 發佈:2019-01-09
我們之前說到比特幣具有很強的安全性和匿名性,這兩點的基礎就在於比特幣的私鑰、公鑰和地址。
私鑰是一串隨機數字,由256位 0 和 1 組成,通常用 16 進製表示,一共有64位。
公鑰則是由私鑰通過橢圓曲線演算法生成的,而此過程是不可逆,也即無法從公鑰推出私鑰。
比特幣地址是一個由數字和字母組成的字串,可以與任何想給你比特幣的人分享。由公鑰生成的比特幣地址以數字“1”開頭。
比特幣地址與公鑰不同。比特幣地址是由公鑰經過單向的雜湊函式生成的。
接下來我們來看一下中本聰先生是如何生成金鑰和將公鑰生成地址的程式碼
//實際程式碼有很多錯誤處理,我們這裡只將流程程式碼貼上來
/*
* NID_secp256k1 是橢圓曲線
* EC_KEY_new_by_curve_name 是OpenSSL的函式,
*/
EC_KEY* pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
//獲取private key
CPrivKey GetPrivKey() const
{
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
if (!nSize)
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
CPrivKey vchPrivKey(nSize, 0);
unsigned char* pbegin = &vchPrivKey[0];
if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
return vchPrivKey;
}
//獲取public key
vector<unsigned char> GetPubKey() const
{
unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
if (!nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
vector<unsigned char> vchPubKey(nSize, 0);
unsigned char* pbegin = &vchPubKey[0];
if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
return vchPubKey;
}
// public key to address
inline string PubKeyToAddress(const vector<unsigned char>& vchPubKey)
{
return Hash160ToAddress(Hash160(vchPubKey));
}
inline string Hash160ToAddress(uint160 hash160)
{
// add 1-byte version number to the front
vector<unsigned char> vch(1, ADDRESSVERSION);
vch.insert(vch.end(), UBEGIN(hash160), UEND(hash160));
return EncodeBase58Check(vch);
}
inline string EncodeBase58Check(const vector<unsigned char>& vchIn)
{
// add 4-byte hash check to the end
vector<unsigned char> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
inline string EncodeBase58(const vector<unsigned char>& vch)
{
return EncodeBase58(&vch[0], &vch[0] + vch.size());
}
inline string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
CAutoBN_CTX pctx;
CBigNum bn58 = 58;
CBigNum bn0 = 0;
// Convert big endian data to little endian
// Extra zero at the end make sure bignum will interpret as a positive number
vector<unsigned char> vchTmp(pend-pbegin+1, 0);
reverse_copy(pbegin, pend, vchTmp.begin());
// Convert little endian data to bignum
CBigNum bn;
bn.setvch(vchTmp);
// Convert bignum to string
string str;
str.reserve((pend - pbegin) * 138 / 100 + 1);
CBigNum dv;
CBigNum rem;
while (bn > bn0)
{
if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
throw bignum_error("EncodeBase58 : BN_div failed");
bn = dv;
unsigned int c = rem.getulong();
str += pszBase58[c];
}
// Leading zeroes encoded as base58 zeros
for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
str += pszBase58[0];
// Convert little endian string to big endian
reverse(str.begin(), str.end());
return str;
}
參考