#include #include "utils.h" #include "mining.h" #include "stratum.h" #include "mbedtls/sha256.h" #include #include #ifndef bswap_16 #define bswap_16(a) ((((uint16_t) (a) << 8) & 0xff00) | (((uint16_t) (a) >> 8) & 0xff)) #endif #ifndef bswap_32 #define bswap_32(a) ((((uint32_t) (a) << 24) & 0xff000000) | \ (((uint32_t) (a) << 8) & 0xff0000) | \ (((uint32_t) (a) >> 8) & 0xff00) | \ (((uint32_t) (a) >> 24) & 0xff)) #endif uint32_t swab32(uint32_t v) { return bswap_32(v); } uint8_t hex(char ch) { uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48); return r & 0x0F; } int to_byte_array(const char *in, size_t in_size, uint8_t *out) { int count = 0; if (in_size % 2) { while (*in && out) { *out = hex(*in++); if (!*in) return count; *out = (*out << 4) | hex(*in++); *out++; count++; } return count; } else { while (*in && out) { *out++ = (hex(*in++) << 4) | hex(*in++); count++; } return count; } } void swap_endian_words(const char * hex_words, uint8_t * output) { size_t hex_length = strlen(hex_words); if (hex_length % 8 != 0) { fprintf(stderr, "Must be 4-byte word aligned\n"); exit(EXIT_FAILURE); } size_t binary_length = hex_length / 2; for (size_t i = 0; i < binary_length; i += 4) { for (int j = 0; j < 4; j++) { unsigned int byte_val; sscanf(hex_words + (i + j) * 2, "%2x", &byte_val); output[i + (3 - j)] = byte_val; } } } void reverse_bytes(uint8_t * data, size_t len) { for (int i = 0; i < len / 2; ++i) { uint8_t temp = data[i]; data[i] = data[len - 1 - i]; data[len - 1 - i] = temp; } } static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0; /* Converts a little endian 256 bit value to a double */ double le256todouble(const void *target) { uint64_t *data64; double dcut64; data64 = (uint64_t *)(target + 24); dcut64 = bswap64(*data64) * 6277101735386680763835789423207666416102355444464034512896.0; data64 = (uint64_t *)(target + 16); dcut64 += bswap64(*data64) * 340282366920938463463374607431768211456.0; data64 = (uint64_t *)(target + 8); dcut64 += bswap64(*data64) * 18446744073709551616.0; data64 = (uint64_t *)(target); dcut64 += bswap64(*data64); return dcut64; } double diff_from_target(void *target) { double d64, dcut64; //reverse_bytes((uint8_t *) target, 32); d64 = truediffone; dcut64 = le256todouble(target); if (unlikely(!dcut64)) dcut64 = 1; return d64 / dcut64; } /****************** PREMINING CALCULATIONS ********************/ bool checkValid(unsigned char* hash, unsigned char* target) { bool valid = true; for(uint8_t i=31; i>=0; i--) { if(hash[i] > target[i]) { valid = false; break; } else if (hash[i] < target[i]) { valid = true; break; } } #ifdef DEBUG_MINING if (valid) { Serial.print("\tvalid : "); for (size_t i = 0; i < 32; i++) Serial.printf("%02x ", hash[i]); Serial.println(); } #endif return valid; } void getNextExtranonce2(int extranonce2_size, char *extranonce2) { unsigned long extranonce2_number = strtoul(extranonce2, NULL, 10); extranonce2_number++; memset(extranonce2, '0', 2 * extranonce2_size); if (extranonce2_number > long(pow(10, 2 * extranonce2_size))) { return; } char next_extranounce2[2 * extranonce2_size + 1]; memset(extranonce2, '0', 2 * extranonce2_size); ultoa(extranonce2_number, next_extranounce2, 10); memcpy(extranonce2 + (2 * extranonce2_size) - long(log10(extranonce2_number)) - 1 , next_extranounce2, strlen(next_extranounce2)); extranonce2[2 * extranonce2_size] = 0; } miner_data init_miner_data(void){ miner_data newMinerData; newMinerData.poolDifficulty = atof(DEFAULT_DIFFICULTY); newMinerData.inRun = false; newMinerData.newJob = false; return newMinerData; } miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ miner_data mMiner = init_miner_data(); // calculate target - target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64) char target[TARGET_BUFFER_SIZE+1]; memset(target, '0', TARGET_BUFFER_SIZE); int zeros = (int) strtol(mJob.nbits.substring(0, 2).c_str(), 0, 16) - 3; memcpy(target + zeros - 2, mJob.nbits.substring(2).c_str(), mJob.nbits.length() - 2); target[TARGET_BUFFER_SIZE] = 0; Serial.print(" target: "); Serial.println(target); // bytearray target size_t size_target = to_byte_array(target, 32, mMiner.bytearray_target); for (size_t j = 0; j < 8; j++) { mMiner.bytearray_target[j] ^= mMiner.bytearray_target[size_target - 1 - j]; mMiner.bytearray_target[size_target - 1 - j] ^= mMiner.bytearray_target[j]; mMiner.bytearray_target[j] ^= mMiner.bytearray_target[size_target - 1 - j]; } // get extranonce2 - extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size) //To review char extranonce2_char[2 * mWorker.extranonce2_size+1]; mWorker.extranonce2.toCharArray(extranonce2_char, 2 * mWorker.extranonce2_size + 1); getNextExtranonce2(mWorker.extranonce2_size, extranonce2_char); mWorker.extranonce2 = String(extranonce2_char); //mWorker.extranonce2 = "00000002"; //get coinbase - coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest() String coinbase = mJob.coinb1 + mWorker.extranonce1 + mWorker.extranonce2 + mJob.coinb2; Serial.print(" coinbase: "); Serial.println(coinbase); size_t str_len = coinbase.length()/2; uint8_t bytearray[str_len]; size_t res = to_byte_array(coinbase.c_str(), str_len*2, bytearray); #ifdef DEBUG_MINING Serial.print(" extranonce2: "); Serial.println(extranonce2); Serial.print(" coinbase: "); Serial.println(coinbase); Serial.print(" coinbase bytes - size: "); Serial.println(res); for (size_t i = 0; i < res; i++) Serial.printf("%02x", bytearray[i]); Serial.println("---"); #endif mbedtls_sha256_context ctx; mbedtls_sha256_init(&ctx); byte interResult[32]; // 256 bit byte shaResult[32]; // 256 bit mbedtls_sha256_starts_ret(&ctx,0); mbedtls_sha256_update_ret(&ctx, bytearray, str_len); mbedtls_sha256_finish_ret(&ctx, interResult); mbedtls_sha256_starts_ret(&ctx,0); mbedtls_sha256_update_ret(&ctx, interResult, 32); mbedtls_sha256_finish_ret(&ctx, shaResult); mbedtls_sha256_free(&ctx); #ifdef DEBUG_MINING Serial.print(" coinbase double sha: "); for (size_t i = 0; i < 32; i++) Serial.printf("%02x", shaResult[i]); Serial.println(""); #endif // copy coinbase hash memcpy(mMiner.merkle_result, shaResult, sizeof(shaResult)); byte merkle_concatenated[32 * 2]; for (size_t k=0; k < mJob.merkle_branch.size(); k++) { const char* merkle_element = (const char*) mJob.merkle_branch[k]; uint8_t bytearray[32]; size_t res = to_byte_array(merkle_element, 64, bytearray); #ifdef DEBUG_MINING Serial.print(" merkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element); #endif for (size_t i = 0; i < 32; i++) { merkle_concatenated[i] = mMiner.merkle_result[i]; merkle_concatenated[32 + i] = bytearray[i]; } #ifdef DEBUG_MINING Serial.print(" merkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element); Serial.print(" merkle concatenated: "); for (size_t i = 0; i < 64; i++) Serial.printf("%02x", merkle_concatenated[i]); Serial.println(""); #endif mbedtls_sha256_context ctx; mbedtls_sha256_init(&ctx); mbedtls_sha256_starts_ret(&ctx,0); mbedtls_sha256_update_ret(&ctx, merkle_concatenated, 64); mbedtls_sha256_finish_ret(&ctx, interResult); mbedtls_sha256_starts_ret(&ctx,0); mbedtls_sha256_update_ret(&ctx, interResult, 32); mbedtls_sha256_finish_ret(&ctx, mMiner.merkle_result); mbedtls_sha256_free(&ctx); #ifdef DEBUG_MINING Serial.print(" merkle sha : "); for (size_t i = 0; i < 32; i++) Serial.printf("%02x", merkle_result[i]); Serial.println(""); #endif } // merkle root from merkle_result Serial.print(" merkle sha : "); char merkle_root[65]; for (int i = 0; i < 32; i++) { Serial.printf("%02x", mMiner.merkle_result[i]); snprintf(&merkle_root[i*2], 3, "%02x", mMiner.merkle_result[i]); } merkle_root[65] = 0; Serial.println(""); // calculate blockheader // j.block_header = ''.join([j.version, j.prevhash, merkle_root, j.ntime, j.nbits]) String blockheader = mJob.version + mJob.prev_block_hash + String(merkle_root) + mJob.ntime + mJob.nbits + "00000000"; str_len = blockheader.length()/2; //uint8_t bytearray_blockheader[str_len]; res = to_byte_array(blockheader.c_str(), str_len*2, mMiner.bytearray_blockheader); #ifdef DEBUG_MINING Serial.println(" blockheader bytes "); Serial.print(str_len); Serial.print(" -> "); #endif // reverse version uint8_t buff; size_t bsize, boffset; boffset = 0; bsize = 4; for (size_t j = boffset; j < boffset + (bsize/2); j++) { buff = mMiner.bytearray_blockheader[j]; mMiner.bytearray_blockheader[j] = mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j]; mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff; } // reverse merkle boffset = 36; bsize = 32; for (size_t j = boffset; j < boffset + (bsize/2); j++) { buff = mMiner.bytearray_blockheader[j]; mMiner.bytearray_blockheader[j] = mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j]; mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff; } // reverse difficulty boffset = 72; bsize = 4; for (size_t j = boffset; j < boffset + (bsize/2); j++) { buff = mMiner.bytearray_blockheader[j]; mMiner.bytearray_blockheader[j] = mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j]; mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff; } #ifdef DEBUG_MINING Serial.print(" >>> bytearray_blockheader : "); for (size_t i = 0; i < 4; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.print("version "); for (size_t i = 0; i < 4; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.print("prev hash "); for (size_t i = 4; i < 4+32; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.print("merkle root "); for (size_t i = 36; i < 36+32; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.print("nbits "); for (size_t i = 68; i < 68+4; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.print("difficulty "); for (size_t i = 72; i < 72+4; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.print("nonce "); for (size_t i = 76; i < 76+4; i++) Serial.printf("%02x", bytearray_blockheader[i]); Serial.println(""); Serial.println("bytearray_blockheader: "); for (size_t i = 0; i < str_len; i++) { Serial.printf("%02x", bytearray_blockheader[i]); } Serial.println(""); #endif return mMiner; }