比特幣原始碼閱讀(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的接口出來!!!!