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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

探索比特币源码7-哈希

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

在之前的兩篇文章中,我們已經大致了解了私鑰和公鑰相關的代碼:

探索比特幣源碼5-私鑰

探索比特幣源碼6-公鑰

接下來,我們打算閱讀生成比特幣地址的相關代碼。

比特幣地址的生成過程中,涉及了哈希函數的計算,這些是更底層的一些實現。

為了更好的進行后面的源碼閱讀,本文先來探索下Bitcoin Core中哈希相關的代碼實現。

哈希值的數據結構

哈希函數可以將任意長度的二進制數據映射為某一固定長度的哈希值,或稱哈希散列

比特幣使用的哈希函數是SHA-256和RIPEMD-160

如何描述這兩種哈希函數映射的結果呢(其實就是 256bit二進制數組 和 160bit二進制數組)?

比特幣系統將相應的數據結構uint256和uint160封裝于uint256.h中

其中,uint256和uint160均繼承自模板基類base_blob

base_blob的描述是:固定大小的不透明二進制大對象blob(Binary Large OBject)的模板基類。

也就是說,我們可以通過繼承base_blob,構造出描述任意長度二進制數據的對象,可用于擴展對于其他哈希函數的散列值的定義。

下面來看uint256.h的源代碼

// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php.#ifndef BITCOIN_UINT256_H #define BITCOIN_UINT256_H#include <assert.h> #include <cstring> #include <stdexcept> #include <stdint.h> #include <string> #include <vector> #include <crypto/common.h>/** Template base class for fixed-sized opaque blobs.* 固定大小的不透明二進制大對象(blob, Binary Large OBject)的模板基類* 模板參數為二進制對象的長度 */ template<unsigned int BITS> class base_blob { protected:static constexpr int WIDTH = BITS / 8; // 字節寬度(雖然是二進制,但也得以byte為單位存儲)uint8_t data[WIDTH]; // 存儲二進制數據的byte數組 public:// 無參數構造函數base_blob(){memset(data, 0, sizeof(data)); // 全0二進制數組,相當于初始化為空}// 使用vector<unsigned char>初始化二進制對象explicit base_blob(const std::vector<unsigned char>& vch);// 二進制對象是否為空(0即是空)bool IsNull() const{for (int i = 0; i < WIDTH; i++)if (data[i] != 0)return false;return true;}// 將二進制對象設置為空void SetNull(){memset(data, 0, sizeof(data));}// 與兩一個二進制對象比較大小(按照memcmp方法比較)inline int Compare(const base_blob& other) const { return memcmp(data, other.data, sizeof(data)); }// 重載 == != < 運算符// 二進制對象的比較涉及到私有成員data,因此定義為友元函數friend inline bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }friend inline bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }friend inline bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }// 獲取二進制對象對應的16進制字符串(注意!代碼采用的小端實現,詳見后文)std::string GetHex() const;// 使用16進制字符串為二進制對象賦值// 注1:16進制字符串應為小端形式// 注2:從源碼實現來看,調用者應自行確保字符串長度與待賦值二進制對象長度的一致性void SetHex(const char* psz);void SetHex(const std::string& str);std::string ToString() const;// 使得base_blob類像vector<T>一樣使用的接口unsigned char* begin(){return &data[0];}unsigned char* end(){return &data[WIDTH];}const unsigned char* begin() const{return &data[0];}const unsigned char* end() const{return &data[WIDTH];}unsigned int size() const{return sizeof(data);}// 讀取二進制對象中的第pos個uint64// 注意也是小端實現,暫不知道該函數作用uint64_t GetUint64(int pos) const{const uint8_t* ptr = data + pos * 8;return ((uint64_t)ptr[0]) | \((uint64_t)ptr[1]) << 8 | \((uint64_t)ptr[2]) << 16 | \((uint64_t)ptr[3]) << 24 | \((uint64_t)ptr[4]) << 32 | \((uint64_t)ptr[5]) << 40 | \((uint64_t)ptr[6]) << 48 | \((uint64_t)ptr[7]) << 56;}template<typename Stream>void Serialize(Stream& s) const{s.write((char*)data, sizeof(data));}template<typename Stream>void Unserialize(Stream& s){s.read((char*)data, sizeof(data));} };/** 160-bit opaque blob.* @note This type is called uint160 for historical reasons only. It is an opaque* blob of 160 bits and has no integer operations.* 如注釋中所述,這個類叫uint160,標識一個160bit的二進制對象,其實跟uint一點關系沒有(估計僅僅是因為中本聰最開始是這么命名的)*/ class uint160 : public base_blob<160> { public:uint160() {}explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {} };/** 256-bit opaque blob.* @note This type is called uint256 for historical reasons only. It is an* opaque blob of 256 bits and has no integer operations. Use arith_uint256 if* those are required.*/ class uint256 : public base_blob<256> { public:uint256() {}explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}/** A cheap hash function that just returns 64 bits from the result, it can be* used when the contents are considered uniformly random. It is not appropriate* when the value can easily be influenced from outside as e.g. a network adversary could* provide values to trigger worst-case behavior.*/// 一個廉價的哈希函數,只從結果中返回64位,當內容被認為是均勻隨機時,可以使用它。// 當值很容易受到來自外部的影響時,例如網絡中的敵對者可以提供值來觸發最壞情況的行為時,這是不合適的。// 此函數的作用尚不明確???uint64_t GetCheapHash() const{return ReadLE64(data);} };/* uint256 from const char *.* This is a separate function because the constructor uint256(const char*) can result* in dangerously catching uint256(0).* 這里作者單獨分離出了一個起到構造函數功能的函數,使用SetHex更安全的返回一個uint256*/ inline uint256 uint256S(const char *str) {uint256 rv;rv.SetHex(str);return rv; } /* uint256 from std::string.* This is a separate function because the constructor uint256(const std::string &str) can result* in dangerously catching uint256(0) via std::string(const char*).*/ inline uint256 uint256S(const std::string& str) {uint256 rv;rv.SetHex(str);return rv; }#endif // BITCOIN_UINT256_H

其中GetHex()函數需要詳細研究下

該函數獲取二進制對象對應的16進制字符串,uint256.cpp中的實現為:

template <unsigned int BITS> std::string base_blob<BITS>::GetHex() const {return HexStr(std::reverse_iterator<const uint8_t*>(data + sizeof(data)), std::reverse_iterator<const uint8_t*>(data)); }

可以看到,GetHex()內部調用utilstrencodings.h中的HexStr方法

在調用的時候,源碼使用了反向迭代器(Reverse Iterator)的技巧。

這說明比特幣系統內部對于哈希散列值,使用小端的方式顯示為16進制字符串。這點我是很疑惑的,遂google之,發現大家對于比特幣的小端實現也是爭議頗多的。

HexStr方法的源代碼如下:

template<typename T> std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) {std::string rv;static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };// 為十六進制字符串分配空間,一個字節轉換為兩個十六進制字符,加上可能存在空格間隔符,因此*3rv.reserve((itend-itbegin)*3);for(T it = itbegin; it < itend; ++it){unsigned char val = (unsigned char)(*it);if(fSpaces && it != itbegin) // 判斷是否需要添加空格間隔符rv.push_back(' ');rv.push_back(hexmap[val>>4]); // 取前4位rv.push_back(hexmap[val&15]); // 取后4位}return rv; }

再來看下SetHex()函數

從uint256.h最后定義的兩個具有類型構造函數功能的函數可以看出,作者應該是更推薦使用SetHex為二進制對象進行賦值。

我們來看看源碼:

template <unsigned int BITS> void base_blob<BITS>::SetHex(const char* psz) {memset(data, 0, sizeof(data));// skip leading spaces 跳過頭部的空白字符while (isspace(*psz)) // isspace判斷參數是否為空白字符(' '、'\t'、'\r'、'\n'、'\v'或'\f')psz++;// skip 0x (不能排除調用者提供的16進制字符串有0x前綴)if (psz[0] == '0' && tolower(psz[1]) == 'x')psz += 2;// hex string to uintconst char* pbegin = psz;// 將psz指向字符串的末尾(注意:比特幣哈希值的16進制字符串為小端實現)while (::HexDigit(*psz) != -1) // HexDigit返回字符char對應的16進制數字,非16進制數字(0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f)返回-1psz++;psz--;unsigned char* p1 = (unsigned char*)data;unsigned char* pend = p1 + WIDTH;while (psz >= pbegin && p1 < pend) {*p1 = ::HexDigit(*psz--);if (psz >= pbegin) { // 檢查下一個字符是否存在(確保16進制字符串成對出現)*p1 |= ((unsigned char)::HexDigit(*psz--) << 4);p1++;}} }

本文就到這里,主要是介紹了用于存儲哈希值的數據結構uint256和uint160,以及他們的基類base_blob。

未完待續…

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。