日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

探索比特币源码5-私钥

發(fā)布時間:2024/7/23 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 探索比特币源码5-私钥 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

經(jīng)過一段時間的積累,終于來到了比特幣源碼閱讀的環(huán)節(jié)。還是按照之前的節(jié)奏,我們就比對著精通比特幣一書的進(jìn)度,進(jìn)行源碼的閱讀。

對于此文,只需你對比特幣系統(tǒng)中私鑰-公鑰-地址的產(chǎn)生及關(guān)系有最基本的了解

因此你可以放心的直接閱讀,如果遇到疑惑,可以返回來閱讀以下資料,填補一些基本概念即可:

  • 精通比特幣第4章
  • 橢圓曲線加密算法教程
  • 密碼學(xué)知識匯總

下面進(jìn)入正題,本文將對比特幣源碼中的私鑰相關(guān)部分進(jìn)行梳理。

在閱讀代碼前,先明確一個概念:私鑰是如何產(chǎn)生的?

私鑰如何產(chǎn)生

比特幣的私鑰就是一個256位二進(jìn)制數(shù)字,就這么簡單。

但是有一個條件,這個256位二進(jìn)制數(shù)要小于一個非常大的質(zhì)數(shù)n

n = 0xffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141

這是由于比特幣使用的橢圓曲線secp256k1的方程所對應(yīng)的循環(huán)子群的秩為n。

這一點了解即可,如果你想了解為什么,建議仔細(xì)閱讀橢圓曲線加密算法教程

也就是說,你可以用硬幣、鉛筆和紙來隨機生成你的私鑰:

擲硬幣256次,用紙和筆記錄正反面并轉(zhuǎn)換為0和1,隨機得到的256位二進(jìn)制數(shù)字可作為比特幣錢包的私鑰,只要其小于n。

當(dāng)然更普遍的方法是使用代碼生成,但是一定要注意:在你不夠了解隨機數(shù)產(chǎn)生器前,不要自己寫代碼或使用你的編程語言提供的簡易隨機數(shù)生成器來獲得一個隨機數(shù)作為私鑰。應(yīng)使用密碼學(xué)安全的偽隨機數(shù)生成器(CSPRNG),并且需要有一個來自具有足夠熵值的源的種子。(這段警告來自于《精通比特幣》,我目前還不知曉怎樣才算一個足夠安全的偽隨機數(shù)發(fā)生器,也望大家告知交流)

代碼閱讀

明確了私鑰的定義,我們來閱讀源碼。

首先,我們進(jìn)入src目錄下

使用ls和grep命令,試圖找到私鑰-公鑰相關(guān)源文件的位置

一番探索后確定,頭文件key.h中的CKey類便是私鑰的定義。

下面是key.h的源碼,我個人的理解直接放在注釋中了

// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2017 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php.#ifndef BITCOIN_KEY_H #define BITCOIN_KEY_H#include <pubkey.h> // 顯然這是定義公鑰的代碼 #include <serialize.h> #include <support/allocators/secure.h> #include <uint256.h>#include <stdexcept> #include <vector>/*** CPrivKey本質(zhì)就是一個vector<unsigned char>* 其allocator在support/allocators/secure.h中進(jìn)行了重載(具體原因暫不清楚)* 這個CPrivKey并不是我們理解的256bit的隨機數(shù)私鑰* 而是一個編碼后的一個私鑰,編碼的私鑰長度為PRIVATE_KEY_SIZE或COMPRESSED_PRIVATE_KEY_SIZE。* 從代碼來看,這個私鑰應(yīng)該是DER編碼的,具體什么是DER,為什么這樣編碼我還不太清楚。*/ typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;/** 封裝的私鑰類. */ class CKey { public:/*** 定義兩個靜態(tài)的大小用來表示普通私鑰的長度和壓縮后私鑰的長度**/static const unsigned int PRIVATE_KEY_SIZE = 279;static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;/*** 壓縮后的私鑰必須要比壓縮前小,這是合理的要求了,使用static_assert在編譯時進(jìn)行檢查*/static_assert(PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,"COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");private:// 用于表示私鑰是否有效// 因為每次key被修改的時候都會做正確性判斷,所以fValid應(yīng)該和真實的狀態(tài)保持一致。bool fValid;// 表示對應(yīng)私鑰的公鑰是否被壓縮bool fCompressed;//! 實際的私鑰數(shù)據(jù)。//! 這里存儲的是我們所熟悉的256bit私鑰(32字節(jié))std::vector<unsigned char, secure_allocator<unsigned char> > keydata;//! 判斷vch指向的32字節(jié)數(shù)據(jù)是否是有效的私鑰數(shù)據(jù)bool static Check(const unsigned char* vch);public:// 構(gòu)造函數(shù),初始化fValid和fCompressed,設(shè)置keydata的長度為32CKey() : fValid(false), fCompressed(false){keydata.resize(32);}// 重載Ckey的==運算符,只要密鑰數(shù)據(jù)一致,是否壓縮也一直,就表示兩個CKey數(shù)據(jù)相同friend bool operator==(const CKey& a, const CKey& b){return a.fCompressed == b.fCompressed &&a.size() == b.size() &&memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0;}// 設(shè)置密鑰的內(nèi)容,并通過check判斷是否為有效密鑰template <typename T>void Set(const T pbegin, const T pend, bool fCompressedIn){if (size_t(pend - pbegin) != keydata.size()) {fValid = false;} else if (Check(&pbegin[0])) {memcpy(keydata.data(), (unsigned char*)&pbegin[0], keydata.size());fValid = true;fCompressed = fCompressedIn;} else {fValid = false;}}// 這塊是簡單的加了幾個方法,能讓CKey的函數(shù)能夠更方便的使用存儲私鑰的成員keydataunsigned int size() const { return (fValid ? keydata.size() : 0); }const unsigned char* begin() const { return keydata.data(); }const unsigned char* end() const { return keydata.data() + size(); }// 返回私鑰是否有效bool IsValid() const { return fValid; }// 返回私鑰(對應(yīng)的公鑰)是否是壓縮格式的bool IsCompressed() const { return fCompressed; }//! 使用隨機的方式創(chuàng)建一個新的密鑰.void MakeNewKey(bool fCompressed);//! 獲得私鑰//! 返回的私鑰是CPrivKey類型的,也就是編碼后的私鑰CPrivKey GetPrivKey() const;//! 獲得公鑰//! 通過私鑰計算出公鑰并返回CPubKey GetPubKey() const;/*** 簽名,返回DER序列化的數(shù)字簽名* @param[in] hash 要進(jìn)行簽名的哈希值* @param[out] 簽名結(jié)果* @param[test_case] 我也沒搞清楚這是干啥的,貌似是傳一個和隨機數(shù)有關(guān)的任意數(shù)*/bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, uint32_t test_case = 0) const;// Create a compact signature (65 bytes)bool SignCompact(const uint256& hash, std::vector<unsigned char>& vchSig) const;// Derive BIP32 child key.bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;// 驗證私鑰和公鑰是否匹配。// 使用的機制并不是使用私鑰再次生成公鑰并比對bool VerifyPubKey(const CPubKey& vchPubKey) const;// 加載一個私鑰,順便判斷下與公鑰是否匹配bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck); };/*** 這也是一個私鑰類型,應(yīng)該是和HD錢包相關(guān)的* CKey, CPubKey, CExtKey, CExtPubKey 是bitcoin core中的四種密鑰實現(xiàn)* 其中CKey, CPubKey是普通的私鑰和公鑰類型* 而如果想使用 HD Wallet,必須使用CExtKey, CExtPubKey* 由于還不了解HD錢包,這個類我也沒有詳細(xì)閱讀* 或許可以看看這個https://medium.com/codechain/hd-wallet-observed-through-bitcoin-core-source-code-ce38f9eab371*/ struct CExtKey {unsigned char nDepth;unsigned char vchFingerprint[4];unsigned int nChild;ChainCode chaincode;CKey key;friend bool operator==(const CExtKey& a, const CExtKey& b){return a.nDepth == b.nDepth &&memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 &&a.nChild == b.nChild &&a.chaincode == b.chaincode &&a.key == b.key;}void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);bool Derive(CExtKey& out, unsigned int nChild) const;CExtPubKey Neuter() const;void SetMaster(const unsigned char* seed, unsigned int nSeedLen);template <typename Stream>void Serialize(Stream& s) const{unsigned int len = BIP32_EXTKEY_SIZE;::WriteCompactSize(s, len);unsigned char code[BIP32_EXTKEY_SIZE];Encode(code);s.write((const char *)&code[0], len);}template <typename Stream>void Unserialize(Stream& s){unsigned int len = ::ReadCompactSize(s);unsigned char code[BIP32_EXTKEY_SIZE];if (len != BIP32_EXTKEY_SIZE)throw std::runtime_error("Invalid extended key size\n");s.read((char *)&code[0], len);Decode(code);} };// 使用橢圓算法加密前必須調(diào)用該程序啟用上下文 void ECC_Start(void);// 使用橢圓加密后使用該函數(shù)銷毀加密上下文 void ECC_Stop(void);// 獲取運行時橢圓曲線需要的支持是否滿足 bool ECC_InitSanityCheck(void);#endif // BITCOIN_KEY_H

下面簡要的閱讀源文件key.cpp

生成一個新的私鑰的方法如下:

bool CKey::Check(const unsigned char *vch) {return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); }void CKey::MakeNewKey(bool fCompressedIn) {do {GetStrongRandBytes(keydata.data(), keydata.size());} while (!Check(keydata.data()));fValid = true;fCompressed = fCompressedIn; }

如前所述,比特幣私鑰其實就是一個256bit隨機數(shù)(32字節(jié)長)

可以看到,代碼中使用GetStrongRandBytes()函數(shù)生成強隨機性的私鑰

使用grep命令搜索該方法

$ grep -rlw "GetStrongRandBytes" * key.cpp random.cpp random.h wallet/wallet.cpp

最終確定,該方法位于random.h中,可在其中探尋詳細(xì)代碼

可以看到MakeNewKey()方法,通過不停調(diào)用GetStrongRandBytes(),直到找到能夠滿足要求的隨機數(shù)作為私鑰

Check()方法調(diào)用libsecp256k1加密庫中的函數(shù)secp256k1_ec_seckey_verify進(jìn)行驗證

獲取私鑰的方法如下

CPrivKey CKey::GetPrivKey() const {assert(fValid);CPrivKey privkey;int ret;size_t privkeylen;privkey.resize(PRIVATE_KEY_SIZE);privkeylen = PRIVATE_KEY_SIZE;ret = ec_privkey_export_der(secp256k1_context_sign, privkey.data(), &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);assert(ret);privkey.resize(privkeylen);return privkey; }

該函數(shù)核心是向ec_privkey_export_der()提供私鑰數(shù)據(jù)keydata(通過begin()傳遞),進(jìn)行DER序列化,并返回CPrivKey類型的私鑰

至于比特幣系統(tǒng)中為什么不傳遞原始的私鑰,而是傳遞DER編碼的私鑰,相信隨著不斷學(xué)習(xí),會得到答案。

獲取公鑰的方法如下

CPubKey CKey::GetPubKey() const {assert(fValid);secp256k1_pubkey pubkey;size_t clen = CPubKey::PUBLIC_KEY_SIZE;CPubKey result;int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());assert(ret);secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);assert(result.size() == clen);assert(result.IsValid());return result; }

可以看到,公鑰的獲取過程首先調(diào)用了libsecp256k1加密庫中的函數(shù)secp256k1_ec_pubkey_create()生成了secp256k1_pubkey類型的公鑰pubkey

然后又調(diào)用libsecp256k1加密庫中的函數(shù)secp256k1_ec_pubkey_serialize將secp256k1_pubkey類型的公鑰序列化為Bitcoin Core中的自定義公鑰類型CPubKey

關(guān)于私鑰的源碼閱讀就到這里。

由于剛剛窺探Bitcoin Core源碼的冰山一角,難免出現(xiàn)理解錯誤的地方,本文中也列出了我目前還不理解的地方,還望各位能夠指出~

總結(jié)

以上是生活随笔為你收集整理的探索比特币源码5-私钥的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 色视频在线免费观看 | 国产成人无码性教育视频 | 亚洲综合图色 | 求av网站| 欧美图片一区二区 | 老司机精品福利导航 | 无码播放一区二区三区 | 少妇被又大又粗又爽毛片久久黑人 | 国产三级一区二区三区 | 一区二区一级片 | 不卡的av电影| 三级全黄做爰在线观看 | 天天爱天天舔 | av女优天堂在线观看 | 中文字幕25页 | 天天想你在线观看完整版电影高清 | 久久精品成人 | 99国产精品一区二区 | 亚洲偷自 | 熟女高潮一区二区三区视频 | 国产成人aaa| 国产精品久久久久久在线观看 | 亚洲精品电影在线观看 | 久草免费在线视频 | 日本天堂在线播放 | 欧美不卡一二三 | 久久视频免费观看 | 国产青草 | h片在线观看免费 | 精品久久无码中文字幕 | javxxx| 9色在线视频 | 97超碰在 | 乌克兰极品av女神 | 艹久久 | 国产精品电影在线观看 | 蜜芽在线视频 | 免费在线观看一区二区 | 9191在线视频 | 亚洲网在线 | 亚州男人的天堂 | 婷婷超碰 | 我把护士日出水了视频90分钟 | 色999在线观看 | 91精品国产乱码久久久久 | 老司机在线观看视频 | 香蕉视频在线网站 | 91爽爽| 中文字幕一区二区视频 | 黄色激情视频在线观看 | 男女做爰真人视频直播 | 精品无人国产偷自产在线 | 国产精品成人一区 | 午夜影院免费观看 | 午夜私人影院 | 国产综合社区 | 手机av网站 | 国产农村妇女精品一区二区 | 国产一级视频在线观看 | 91插插插插插插插 | 99在线观看免费视频 | 9久精品 | 欧美成人国产va精品日本一级 | 无码人妻aⅴ一区二区三区 国产高清一区二区三区四区 | 亚洲国产精品99久久久久久久久 | av影视在线观看 | 高清视频在线播放 | www黄色网| gogo人体做爰大胆视频 | 性av网站 | 久久久久99人妻一区二区三区 | 阿v免费视频| 久操影视| jizz国产 | 国产极品在线播放 | 国产不卡一 | 欧美亚洲在线播放 | 天天碰免费视频 | gai免费观看网站外网 | 久久久久亚洲av成人片 | 国产91色在线 | 67194成人在线观看 | 91久久久国产精品 | 这里只有精品视频在线 | 伦在线 | 色开心| 亚洲欧美一区二区三区在线 | 性生活三级视频 | 邵氏电影《金莲外传2》免费观看 | 欧美成人综合视频 | 在线观看av国产一区二区 | 美女伦理水蜜桃4 | 亚洲高清资源 | 亚洲网址| 国产精品九色 | 怡红院国产 | 国产成人免费观看视频 | 国产精品久久亚洲 | 欧美成人综合色 |