0

I am currently in the process of creating a simple bitcoin miner in c++, and need some help optimizing part of it.

I have a string in hexadecimal value, which is parsed into binary (code below) due to the need to run the OpenSSL sha256 hashing function on it. I need to continuous do sha256 hashing, however each time the last 8 chars of the hexadecimal value need to be incremented.

Currently I do this by converting the binary value back to an hexadecimal value, convert the last 8 chars of that to a long, increment the long, and then convert the whole thing back to binary again, which of course is highly inefficient.

What is the most optimal way of incrementing the binary value?

// parse an hexidemical string into a binary format
void toBytes(std::string input,unsigned char *result){
    for(int i=0, j=0; i < input.size(); j++, i+=2) {
        std::string twoChars = input.substr(i,2);
        result[j] = (unsigned char)std::stoi(twoChars,0,16);
    }
}
// converts a binary unsigned char into a hexademical string
std::string toHex(unsigned char* data, int len) {
    std::string result(""); 
    char buf[2];        
    int c;        
    c=0;
    while(c < len) {
        sprintf(buf,"%.2x", data[c++]);
        result+=buf;
    }
    return result;
}

Here's my current, and very inefficient addition:

void addNonce(unsigned char * binary, int length) {
    std::string hex = toHex(binary, length);
    std::string nonceString = hex.substr(152,8);
    long nonce = std::strtol(hex.substr(152,8).c_str(),NULL,16 );
    nonce++;
    char buf[8];
    sprintf(buf, "%.8lx", nonce);   
    hex.replace(152,8,buf);
    toBytes(hex,binary);
}

Here's an example of an incrementation in hexadecimal format (I need to increment once, then hash that, increment again, hash, until the maximum value):

020000001fba9705b223d40c25b0aba35fee549aa477307862fb45ad18020000
0000000033d14883e297679e3f9a5eb108dab72ff0998e7622e427273e90027e
312ba443105315513c1f051a00000000

020000001fba9705b223d40c25b0aba35fee549aa477307862fb45ad18020000
0000000033d14883e297679e3f9a5eb108dab72ff0998e7622e427273e90027e
312ba443105315513c1f051a00000001

Up to the maximum value

020000001fba9705b223d40c25b0aba35fee549aa477307862fb45ad18020000
0000000033d14883e297679e3f9a5eb108dab72ff0998e7622e427273e90027e
312ba443105315513c1f051aFFFFFFFF
Jacob
  • 3,521
  • 6
  • 26
  • 34
  • 1
    Is there a reason that you are keeping the data in ASCI represented string instead of simply in it's binary format? I would imagine that simply keeping it in it's binary element, performing all operations on that data, then dumping the final output to a string as output (if that's desired) would both simplify and speed up the process. – Aumnayan Jul 01 '14 at 14:44
  • Well I get the input as a hexadecimal string that I convert into binary (with the code in the question), and then I need to do hashing on this binary code, but incrementing the values in the end as illustrated by the example (in hex). I am not sure how do to do desired incrementation operation in its binary form - that is exactly what I am asking help for. – Jacob Jul 01 '14 at 14:49
  • As Aumnayan says, it will be *much* faster to keep everything in raw integer ("binary") form throughout. Incrementing a multi-byte (or multi-word) integer works just like incrementing a number in decimal: you add 1 to the rightmost digit (byte), and if it stays within its range you stop there; otherwise you wrap it back to 0 and increment the digit (byte) to its left, repeating this as often as necessary. The 2's complement representation used for integers on all modern computers helps you here because incrementing the highest byte value automatically wraps it. – j_random_hacker Jul 01 '14 at 14:56
  • Any number representation of the full value overflows I am afraid. – Jacob Jul 01 '14 at 14:57
  • You don't need the full value -- you only need to consider 1 byte at a time! – j_random_hacker Jul 02 '14 at 03:11

1 Answers1

2

Got ya.

void addNonce(unsigned char * binary, int length) {
    unsigned long *nonce = (unsigned long*) &binary[length-4];
    (*nonce)++;
}

I think this (or something very like it) is what you're looking for. I'm not 100% on the array placement in the binary array, but suspect it's good.

When the value at nonce overflows it should get reset to 0. I'm not sure if that's the desired behaviour or not, but adding a small bit of overflow protection around nonce shouldn't be to expensive if another result is desired.

Aumnayan
  • 671
  • 3
  • 12
  • I am making sure that it doesn't overflow from FFFFFFFF. The code gives this 00000000->01000000->02000000 on the final bits instead of 00000000->00000001->00000002 – Jacob Jul 01 '14 at 15:13
  • Then you need to endian convert *nonce, incriment it, and endian convert it again. It would look something like *nonce = hton(hton(*nonce)++); – Aumnayan Jul 01 '14 at 15:29
  • This answer assumes that `unsigned long` is 4 bytes long (sometimes true, sometimes not), that the machine representation of integers is big-endian (*not* true on the most common platform, x86/x64) and it only increments the bottom 4 bytes, not all 8. – j_random_hacker Jul 02 '14 at 03:14
  • 1
    Yes, it does assume that long is 4 bytes. I felt this safe as the author does the same in his code. I also assumed an endianness of the machine, which the author disproved in his comments which I subsequently provide a solution for above, though I didn't edit the base answer. The author in his question wants to increment "the last 8 chars" of an hex representation ascii string, which is 4 bytes, and within the scope of the answer. – Aumnayan Jul 02 '14 at 14:42
  • 1
    Ah, I overlooked that 8 hex digits = only 4 bytes. In that case my only suggestion is to write `uint32_t` instead of `unsigned long` so that this will still work when compiling in 64-bit mode. – j_random_hacker Jul 02 '14 at 18:34