Mining-Theory

在 C++ 中對塊頭進行雙重散列時使用的實際工作實現程式碼是什麼?

  • January 13, 2022

我需要根據我認為到目前為止被描述為十六進製過濾的 sha256 實現……或類似的東西成功地生成一個雜湊值。我來過這裡這裡這裡這里這裡……在許多其他地方。


範例案例:

使用“abc”作為輸入字元串, 勾選**“Hex”複選框的**AnyHash.com 會生成一個雜湊 - 。當作為輸入輸入時,它會產生雜湊 - 。15f27c6b8828e62cd3d09e8b4de5230844facfc88f1b9c34129cab7706f2f56115f27c6b8828e62cd3d09e.......42a5aa8cd08811f43428c42f76279a5a92e12b3e3f7080b87804a05135773487

根據dave_thompson_085評論,我一直在努力讓它發揮作用。使用中的 sha256 實現是由Zedwood提供的,下面是我為重新創建由AnyHash.com生成的雜湊輸出而進行的徒勞的努力。


//  -----------------------                 --------------------------- //
//  -----------------------                 --------------------------- //
//  -----------------------                 --------------------------- //
// COMMENT BY DAVE_THOMPSON_085

// That code is okay except the silly std::string wrapper is useless for bitcoin. Do something like :
// unsigned char hdr[80], hash[32];
// SHA256 ctx = SHA256();

/* fill in hdr */
// ctx.init();
// ctx.update(hdr,80);
// ctx.final(hash);
// ctx.init();
// ctx.update(hash,32);
// ctx.final(hash);
/* (reverse and) use results in hash, possibly converted to hex or whatever you need */

//  -----------------------                 --------------------------- //
//  -----------------------                 --------------------------- //
//  -----------------------                 --------------------------- //

std::string sha256(std::string input)
{
   string kk;
   // header_data is "160" in size because midstate optimization is not implemented
   unsigned char header_data[160], hash[32];
   char hash2[32], hash3[32];
   char buf[2*32+1];
   buf[2*32] = 0;

   // input = GetBinaryStringFromHexString(input); // convert input data to binary format
   init();
   update((unsigned char*)input.c_str(), input.length());
   final(hash);

   // Iterate and store values from hash[] to hash2[]
   for (int i = 0; i < 32; i++)
       hash2[i] = hash[i];

   // kk = final2(hash); // MODIFIED FUNCTION THAT RETURNS A STRING 
   // //kk = char_ToString(hash2); // Converts char array to string variable
   kk = GetBinaryStringFromHexString(char_ToString(hash2)); // convert data to binary format
   input = kk; // Store data in kk to input
   init();
   update((unsigned char*)input.c_str(), input.length());
   final((unsigned char *)hash3); // Modified as char* to unsigned char* conversion is not allowed


   for (int i = 0; i < 32; i++) 
       sprintf(buf+i*2, "%02x", hash3[i]); // ORIGINAL : sprintf(buf+i*2, "%02x", digest[i])

   return std::string(buf); // Return buf as string instead of char
}


int main(int argc, char const *argv[])
{
   std::string data = "abc";
   std::cout << "sha256(data) : " << sha256(data) << "\n";
   std::cout << "sha256(sha256(data)) :  " << sha256(sha256(data)) << "\n";
   return 0;
}

//  Input : abc
//  Expecting first hash output from sha256 ( with hex conversion ) to be :
// 15f27c6b8828e62cd3d09e8b4de5230844facfc88f1b9c34129cab7706f2f561 - single sha

//  And second output to be : 
// 42a5aa8cd08811f43428c42f76279a5a92e12b3e3f7080b87804a05135773487 - double sha

//  As generated byanyhash.com

有時最難實現的總是顯而易見的實現。- 在我看來。

**勾選了“Hex”**的相同雜湊生成器成功生成了比特幣區塊鏈中存在的第100000 塊的正確雜湊。區塊 100,000 由 AnyHash.com 散列

塊頭**0100000050120119172a610421a6c3011dd330d9df07b63616c2cc1f1cd00200000000006657a9252aacd5c0b2940996ecff952228c3067cc38d4885efb5a4ac4247e9f337221b4d4c86041b0f2b5710**

我嘗試從比特幣原始碼中獲取程式碼**hahahahahahahahahahahaha…….**需要我多說嗎?

包含如此多的標頭和超出所需的依賴項,想想它就是一場噩夢。所以,如果有人知道如何真正使這段程式碼工作……請協助其他程序員……

天知道比特幣讓大多數程序員看起來像個新手。仍然是一項偉大的技術!

以下是使用的其他功能(如果它有問題)提前謝謝!

sing std::hex;

string GetBinaryStringFromHexString(string hexData);
// std::string char_ToString(char data[]);

std::string char_ToString(char data[])
{
   std::string stringData = ""; //declare string variable
   // int size = sizeof(data)/sizeof(*data); 
   int size =  strlen(data); //get amount of characters in char array
   for (int i = 0; i < size; i++) // for elements in char array
       stringData = data; // store elements in string variable "stringData"
   return stringData; // return stringData
}


string GetBinaryStringFromHexString(string hexData)
{
   string binaryResult = "";
   for (int i = 0; i < hexData.length(); ++i)
   {
       switch (hexData[i])
       {
       case '0':
           binaryResult.append("0000");
           break;
       case '1':
           binaryResult.append("0001");
           break;
       case '2':
           binaryResult.append("0010");
           break;
       case '3':
           binaryResult.append("0011");
           break;
       case '4':
           binaryResult.append("0100");
           break;
       case '5':
           binaryResult.append("0101");
           break;
       case '6':
           binaryResult.append("0110");
           break;
       case '7':
           binaryResult.append("0111");
           break;
       case '8':
           binaryResult.append("1000");
           break;
       case '9':
           binaryResult.append("1001");
           break;
       case 'a':
           binaryResult.append("1010");
           break;
       case 'b':
           binaryResult.append("1011");
           break;
       case 'c':
           binaryResult.append("1100");
           break;
       case 'd':
           binaryResult.append("1101");
           break;
       case 'e':
           binaryResult.append("1110");
           break;
       case 'f':
           binaryResult.append("1111");
           break;
       }
   }
   return binaryResult;
}

請注意,我正在分析您的程式碼,就好像我按原樣編譯它一樣。這意味著任何被註釋掉的東西都會被忽略。


第一個主要問題是這一行:

   kk = GetBinaryStringFromHexString(char_ToString(hash2)); // convert data to binary format

較早的final(hash);將生成一個 char 數組,其中填充了 SHA256 雜湊作為二進制數據。因此,無需將其轉換為 std::string 並隨後嘗試將其轉換為二進製字元串。此行是不必要的,hash可以直接作為下一行的輸入提供update()。解決這個問題應該可以讓您找到abc.

這段程式碼的第二個主要問題是它GetBinaryStringFromHexString沒有做你認為它正在做的事情。它將十六進製字元串轉換為二進製字元串。這與將十六進製字元串轉換為該十六進製表示的二進制數據不同。您在該函式中實際得到的是一個更長的字元串,其數據是 0 和 1 的 ascii 字元,而不是十六進製字元串本身表示的數據。這個StackOverflow 答案提供了一個可以使用的十六進製字元串解析函式。修復此問題應該允許您找到以十六進製字元串形式提供的塊頭的雙 SHA256。


幾個小問題:

  1. 無需複製hashhash2. 您也可以直接將其作為參數提供給第二個update
  2. 沒有必要有hash2hash3。您每次都可以使用hash,它將被新的雜湊覆蓋。final
  3. 該功能char_ToString不是必需的。除此之外,您的程式碼不需要它,std::string還有一個可以採用 a及其長度的建構子。char *

您的最終程式碼將類似於:

std::string sha256(std::string input)
{
   string kk;
   // header_data is "160" in size because midstate optimization is not implemented
   unsigned char header_data[160], hash[32];
   char buf[2*32+1];
   buf[2*32] = 0;

   input = ParseHex(input);
   init();
   update((unsigned char*)input.c_str(), input.length());
   final(hash);
   
   init();
   update(hash, 32);
   final(hash);

   for (int i = 0; i < 32; i++) 
       sprintf(buf+i*2, "%02x", hash[i]); // ORIGINAL : sprintf(buf+i*2, "%02x", digest[i])

   return std::string(buf); // Return buf as string instead of char
}

std::string ParseHex(const std::string& s)
{
   assert(s.size() % 2 == 0);
   static const std::size_t symbol_count = 256;
   static const unsigned char hex_to_bin[symbol_count] = {
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2F
                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37
                0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3F
                0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x40 - 0x47
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5F
                0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x60 - 0x67
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9F
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 - 0xA7
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 - 0xAF
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0 - 0xB7
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 - 0xBF
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 - 0xC7
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 - 0xCF
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 - 0xD7
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 - 0xDF
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 - 0xE7
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 - 0xEF
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 - 0xF7
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 0xF8 - 0xFF
              };

   std::string out;
   auto& itr = s.begin();
   while (itr != s.end())
   {
      unsigned char b = static_cast<unsigned char>(hex_to_bin[*(itr++)] << 4);
      b |= static_cast<unsigned char>(hex_to_bin[*(itr++)]     );
      out.push_back(b);
   }
   return out;
}

引用自:https://bitcoin.stackexchange.com/questions/111748