1. 程式人生 > >比特幣原始碼閱讀(1)--雜記與加密部分(爽之小刀)

比特幣原始碼閱讀(1)--雜記與加密部分(爽之小刀)

比特幣原始碼閱讀(1)–雜記與加密部分(爽之小刀)

歡迎轉載和引用
若有問題請聯絡請聯絡
Email : [email protected]
QQ:2279557541


最近從成都來到了杭州拼一槍
由於老婆為了圓自己的一個大公司夢來到了杭州
而我也很坎坷
經歷了
創業(自動化行業,非創始人),然後雖然上了新三版,但是手裡的股票和廢紙一樣沒辦法交易。
打工(被老闆欠薪),老闆每月要給我降薪1w,我只能選擇辭職,但是去年的錢老闆還差我7,8w的樣子,我問他要,他說要我繼續維護公司程式碼,維護至少1年才可能給我。。。這。。。唉~~~~~
為了實現財富自由,我來到了杭州,一方面離老婆近點,一方面,為了財富自由拼一槍吧。
我進入了區塊連開發這行!
開始找了很多公司都不要我,也許我要的薪資太高了,我要的3w,但是我發現我太高看自己了。。。根本沒人願意這個價格招我這個小菜鳥。。。不過既然來了杭州就不能灰頭土臉的走。
終於有一家公司願意要我了,做的公鏈,發幣的(我心中也覺得只有公鏈才有前景),和我的想法不謀而合,而且薪資也不低,夠我活下去了,和老闆(相當年輕,慚愧啊)在星巴克聊了辦小時,一拍即和!就這麼定了!不過公司剛起步,私募貌似剛完成,公幕剛開始。我是第一個過來的研發。。。還有個哥們經驗比我豐富些,但是區塊連完全沒接觸過,不過他經驗豐富,希望用rust來開發,那我當然不會抗拒了,畢竟多學門手藝也是件好事!

於是想讓大哥帶我的想法就這麼泡湯了。。。不過竟然這麼多人都能做公鏈,我相信我也不會有多大問題,我們要做一個基於dag的共識,花了1周基本理解了dag鏈的構架!
現在我打算寫加密部分,不二選讀懂比特幣,然後抄思想,改程式碼,翻譯成rust,畢竟剛起步,創新什麼的等到第一版出來再說吧!
下面不如正題,我第一個看的是比特幣的key.cpp和key.h這兩個檔案
cpp沒啥好說的先看h檔案,看懂整個思路,在研究cpp的演算法部分。
我現在最關心私鑰-》公鑰-》地址是怎麼回事。。。
翻遍了google,沒人是繼續程式碼說這個事情的,只有自己來了

// 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> /** * (PRIVATE_KEY_SIZE bytes) * CPrivKey是一個包含了所有引數序列化後的一個私鑰,包含了所有引數的私鑰長度為PRIVATE_KEY_SIZE。 */ typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey; /** An encapsulated private key. */ class CKey { public: /** * 定義兩個靜態的大小用來表示普通私鑰的長度和壓縮後私鑰的長度 */ static const unsigned int PRIVATE_KEY_SIZE = 279; static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; /** * 壓縮後的私鑰必須要比壓縮前小,這是合理的要求了,使用static_assert表示是在編譯時檢查的 */ static_assert( PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); private: //!用於表示私鑰是否有效 //! 因為每次key被修改的時候都會做正確性判斷,所以fValid應該和真實的狀態保持一致。 bool fValid; //! 表示對應私鑰的公鑰是否被壓縮 bool fCompressed; //! 實際的私鑰16進位制資料。 std::vector<unsigned char, secure_allocator<unsigned char> > keydata; //! Check whether the 32-byte array pointed to by vch is valid keydata. //! 判斷vch指向的32位元組資料是否是有效的金鑰資料???金鑰?私鑰?公鑰? bool static Check(const unsigned char* vch); public: //! 建構函式,其實啥也美感,就是設定keydata的長度為32 CKey() : fValid(false), fCompressed(false) { keydata.resize(32); } //! 過載==符號,只要金鑰資料一致,是否壓縮也一直,就表示兩個CKey資料相同 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; } //! 設定金鑰的內容,並通過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像一個vector一樣用,但其實也不是完全vector畢竟他沒有過載[] unsigned 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(); } //! 通過fValid判斷他是否是有效的 bool IsValid() const { return fValid; } //! 判斷是否是被壓縮過的 bool IsCompressed() const { return fCompressed; } //! 使用隨機的方式建立一個新的金鑰. void MakeNewKey(bool fCompressed); /** * 將CKey轉換為CPrivKey,也就是包含更多引數的CKey而已???哪些引數 */ CPrivKey GetPrivKey() const; /** * 通過私鑰計算出一個公鑰 */ CPubKey GetPubKey() const; /** * 用於簽名的函式,其中test_case使用來調整簽名的 * @param[in] hash 要進行加密的雜湊值 * @param[out] 簽名結果 * @param[test_case] 我也沒搞清楚這是幹啥的,貌似是傳一個和隨機數有關的任意數 */ bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, uint32_t test_case = 0) const; /** * 用於建立壓縮簽名的函式 */ bool SignCompact(const uint256& hash, std::vector<unsigned char>& vchSig) const; //! 貌似是用來擴充套件金鑰的 bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; /** * 判斷一個公鑰是不是一個私鑰產生的 */ bool VerifyPubKey(const CPubKey& vchPubKey) const; //! 載入一個私鑰,順便判斷下公鑰是否是私鑰算出來的,若fSkipCheck為ture,則不判斷 bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck); }; /** * 這個貌似是用於使用BIP擴充套件金鑰的,稱之為比特幣改進協議BIP32 */ 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); } }; /** 使用橢圓演算法加密前必須呼叫該程式啟用上下文 */ void ECC_Start(void); /** 使用橢圓加密後使用該函式哦銷燬加密上下文 */ void ECC_Stop(void); /** Check that required EC support is available at runtime. */ bool ECC_InitSanityCheck(void); #endif // BITCOIN_KEY_H

這裡面的函式我基本都測試過,過段時間封裝個rust的接口出來!!!!