0

I want to hash a block header in C++ but dont know how.

Im just using a test block at the moment, so that I know what the expected outcome is. https://www.blockchain.com/btc/block/669892

I have a function which formats the block header into the hex string of 0000ff3fd90c0dfca35c8738aa92e1c5bdf706ba14eaafbb379206000000000000000000ad66d8cda0330c3af011ba6b7bc705789767c55a72a818685b3e06a0b8b9a2b054e82260b9210d17099976a6

Now, im struggling to properly hash this to the expected 000000000000000000064ec839564cc03166184f0a404d82cad9c655f714d886

static void calcHash(std::string hash){
    CryptoPP::SHA256 hash;
    std::string digest;
    CryptoPP::StringSource(data, true, 
        new CryptoPP::HashFilter(hash, new 
            CryptoPP::HexEncoder(new CryptoPP::StringSink(digest)
    )));
    std::cout << "digest: " << digest << std::endl;

    CryptoPP::SHA256 hash2;
    std::string digest2;
    CryptoPP::StringSource(digest, true, 
        new CryptoPP::HashFilter(hash2, new 
            CryptoPP::HexEncoder(new CryptoPP::StringSink(digest2)
    )));
    std::cout << "digest2: " << digest2 << std::endl;

   return digest2;
}

When I pass that header through this function, i do not get the expected.

How do I get the expected hash from my formatted header using c++?

6
  • The hash ending d886 isn't the hash of the header, it's the hash of the whole block.
    – Jivan Pal
    Commented Feb 11, 2021 at 17:52
  • Then I must be at a misunderstanding, I thought you calculate the header hash to compare with the target. Am I wrong? Commented Feb 11, 2021 at 18:12
  • Apologies, yes, it is just the hash of the header, but historically it was the hash of the whole block. Nowadays, the header is tied to the transaction set via its Merkle root.
    – Jivan Pal
    Commented Feb 11, 2021 at 18:15
  • To clarify, you are trying to compute the hash of the header of BTC block 669892, and you have computed that the binary/hex representation of that header is 0000ff3fd...?
    – Jivan Pal
    Commented Feb 11, 2021 at 18:25
  • Is the result you're getting? 86d814f755c6d9ca824d400a4f186631c04c5639c84e06000000000000000000
    – Jivan Pal
    Commented Feb 11, 2021 at 20:57

1 Answer 1

1

Firstly, you have a name conflict; hash is both the std::string argument passed to calcHash(), and also the name of your CryptoPP::SHA256 object. This code won't even compile, so are you sure this is the code you're using?

The code itself is somewhat difficult to read, too, because you pass around anonymous objects to nested constructors in an attempt to be concise, but this just makes things needlessly confusing to the reader. Perhaps you have copy-pasted one-liners from other places?

Anyway, here's the approach you should take:

  1. Use HexDecoder (not HexEncoder) to convert your input string (let's call it headerString) to a byte array of the data represented by that hexadecimal string (call the result headerData).

  2. Hash headerData using SHA-256 twice using the CalculateDigest() method of a CryptoPP::SHA256 object, storing the result in a byte array (call it hash2, because we call the first hash hash1).

  3. Use HexEncoder to convert hash2 into a string which is a hexadecimal representation of the hash (call it hashString).

Here's that in code:

#include <iostream>

using namespace std;
using namespace CryptoPP;

static void printHash(std::string headerString) {
    // Convert hex string to byte array
    string headerData;
    HexDecoder decoder = new HexDecoder(new StringSink(headerData));
    decoder.Put((byte*)headerString.data(), headerString.size());
    decoder.MessageEnd();

    // Hash the byte array twice
    SHA256 hasher;

    byte hash1[SHA256::DIGESTSIZE];
    hasher.calculateDigest(hash1, (byte*)headerData.data(), headerData.size());
    
    byte hash2[SHA256::DIGESTSIZE];
    hasher.calculateDigest(hash2, hash1, hash1.length);

    // Convert result to hex string
    string hashString;
    HexEncoder encoder = new HexEncoder(new StringSink(hashString));
    encoder.Put(hash2, sizeof(hash2));
    encoder.MessageEnd();

    // Print the hash
    cout << asLowerCase(hashString) << endl;
}
1
  • Thank you very much Jivan!! As a C++ newby, this has put to rest my couple days of trial and error! I have tried this, edited to fit, and it works as expected!! Commented Feb 11, 2021 at 21:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.