diff --git a/miner/core/CMakeLists.txt b/miner/core/CMakeLists.txt index 2fbd480..e313dc6 100644 --- a/miner/core/CMakeLists.txt +++ b/miner/core/CMakeLists.txt @@ -11,6 +11,7 @@ option(WITH_ARGON2 "Enable Argon2 algorithms family" ON) option(WITH_KAWPOW "Enable KawPow algorithms family" ON) option(WITH_ETCHASH "Enable ETChash/Ethash algorithms family" ON) option(WITH_PROGPOWZ "Enable ProgPowZ algorithm (Zano)" ON) +option(WITH_BLAKE3DCR "Enable Blake3DCR algorithm (Decred)" ON) option(WITH_GHOSTRIDER "Enable GhostRider algorithm" ON) option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON) option(WITH_DEBUG_LOG "Enable debug log output" OFF) @@ -205,6 +206,7 @@ include(cmake/argon2.cmake) include(cmake/kawpow.cmake) include(cmake/etchash.cmake) include(cmake/progpowz.cmake) +include(cmake/blake3dcr.cmake) include(cmake/ghostrider.cmake) include(cmake/OpenSSL.cmake) include(cmake/asm.cmake) @@ -241,7 +243,7 @@ if (WITH_DEBUG_LOG) endif() add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES}) -target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB} ${ARGON2_LIBRARY} ${ETHASH_LIBRARY} ${GHOSTRIDER_LIBRARY}) +target_link_libraries(${CMAKE_PROJECT_NAME} ${XMRIG_ASM_LIBRARY} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB} ${ARGON2_LIBRARY} ${ETHASH_LIBRARY} ${GHOSTRIDER_LIBRARY} ${BLAKE3_LIBRARY}) if (WIN32) if (NOT ARM_TARGET) diff --git a/miner/core/cmake/blake3dcr.cmake b/miner/core/cmake/blake3dcr.cmake new file mode 100644 index 0000000..a1ab240 --- /dev/null +++ b/miner/core/cmake/blake3dcr.cmake @@ -0,0 +1,17 @@ +if (WITH_BLAKE3DCR) + add_definitions(/DXMRIG_ALGO_BLAKE3DCR) + + list(APPEND HEADERS_CRYPTO + src/crypto/blake3dcr/Blake3DCR.h + ) + + list(APPEND SOURCES_CRYPTO + src/crypto/blake3dcr/Blake3DCR.cpp + ) + + # Add Blake3 library + add_subdirectory(src/3rdparty/blake3) + set(BLAKE3_LIBRARY blake3) +else() + remove_definitions(/DXMRIG_ALGO_BLAKE3DCR) +endif() diff --git a/miner/core/src/3rdparty/blake3/CMakeLists.txt b/miner/core/src/3rdparty/blake3/CMakeLists.txt new file mode 100644 index 0000000..f8e9a23 --- /dev/null +++ b/miner/core/src/3rdparty/blake3/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.5) +project(blake3 C) + +set(BLAKE3_SOURCES + blake3.c +) + +set(BLAKE3_HEADERS + blake3.h +) + +add_library(blake3 STATIC ${BLAKE3_SOURCES} ${BLAKE3_HEADERS}) + +target_include_directories(blake3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/miner/core/src/3rdparty/blake3/blake3.c b/miner/core/src/3rdparty/blake3/blake3.c new file mode 100644 index 0000000..4350c46 --- /dev/null +++ b/miner/core/src/3rdparty/blake3/blake3.c @@ -0,0 +1,342 @@ +/* + * BLAKE3 reference implementation + * Based on https://github.com/BLAKE3-team/BLAKE3 + * + * This is a minimal portable C implementation for Decred mining. + */ + +#include "blake3.h" +#include + +// Initial vector +static const uint32_t IV[8] = { + BLAKE3_IV_0, BLAKE3_IV_1, BLAKE3_IV_2, BLAKE3_IV_3, + BLAKE3_IV_4, BLAKE3_IV_5, BLAKE3_IV_6, BLAKE3_IV_7 +}; + +// Message schedule permutation +static const uint8_t MSG_SCHEDULE[7][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}, + {3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1}, + {10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6}, + {12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4}, + {9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7}, + {11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13}, +}; + +static inline uint32_t load32_le(const uint8_t *src) { + return ((uint32_t)src[0]) | ((uint32_t)src[1] << 8) | + ((uint32_t)src[2] << 16) | ((uint32_t)src[3] << 24); +} + +static inline void store32_le(uint8_t *dst, uint32_t w) { + dst[0] = (uint8_t)(w); + dst[1] = (uint8_t)(w >> 8); + dst[2] = (uint8_t)(w >> 16); + dst[3] = (uint8_t)(w >> 24); +} + +static inline uint32_t rotr32(uint32_t w, unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +// Quarter round +static inline void g(uint32_t *state, size_t a, size_t b, size_t c, size_t d, + uint32_t x, uint32_t y) { + state[a] = state[a] + state[b] + x; + state[d] = rotr32(state[d] ^ state[a], 16); + state[c] = state[c] + state[d]; + state[b] = rotr32(state[b] ^ state[c], 12); + state[a] = state[a] + state[b] + y; + state[d] = rotr32(state[d] ^ state[a], 8); + state[c] = state[c] + state[d]; + state[b] = rotr32(state[b] ^ state[c], 7); +} + +static inline void round_fn(uint32_t state[16], const uint32_t *msg, size_t round) { + const uint8_t *schedule = MSG_SCHEDULE[round]; + g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]); + g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]); + g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]); + g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]); + g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]); + g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]); + g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]); + g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]); +} + +static void compress_pre(uint32_t state[16], const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags) { + uint32_t msg[16]; + for (size_t i = 0; i < 16; i++) { + msg[i] = load32_le(block + 4 * i); + } + + state[0] = cv[0]; + state[1] = cv[1]; + state[2] = cv[2]; + state[3] = cv[3]; + state[4] = cv[4]; + state[5] = cv[5]; + state[6] = cv[6]; + state[7] = cv[7]; + state[8] = IV[0]; + state[9] = IV[1]; + state[10] = IV[2]; + state[11] = IV[3]; + state[12] = (uint32_t)counter; + state[13] = (uint32_t)(counter >> 32); + state[14] = block_len; + state[15] = flags; + + for (size_t round = 0; round < 7; round++) { + round_fn(state, msg, round); + } +} + +static void compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags) { + uint32_t state[16]; + compress_pre(state, cv, block, block_len, counter, flags); + cv[0] = state[0] ^ state[8]; + cv[1] = state[1] ^ state[9]; + cv[2] = state[2] ^ state[10]; + cv[3] = state[3] ^ state[11]; + cv[4] = state[4] ^ state[12]; + cv[5] = state[5] ^ state[13]; + cv[6] = state[6] ^ state[14]; + cv[7] = state[7] ^ state[15]; +} + +static void compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags, + uint8_t out[64]) { + uint32_t state[16]; + compress_pre(state, cv, block, block_len, counter, flags); + for (size_t i = 0; i < 8; i++) { + store32_le(&out[i * 4], state[i] ^ state[i + 8]); + } + for (size_t i = 8; i < 16; i++) { + store32_le(&out[i * 4], state[i] ^ cv[i - 8]); + } +} + +// Chunk state functions +static void chunk_state_init(blake3_chunk_state *self, const uint32_t key[8], uint8_t flags) { + memcpy(self->cv, key, BLAKE3_KEY_LEN); + self->chunk_counter = 0; + memset(self->buf, 0, BLAKE3_BLOCK_LEN); + self->buf_len = 0; + self->blocks_compressed = 0; + self->flags = flags; +} + +static size_t chunk_state_len(const blake3_chunk_state *self) { + return (BLAKE3_BLOCK_LEN * (size_t)self->blocks_compressed) + (size_t)self->buf_len; +} + +static size_t chunk_state_fill_buf(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { + size_t take = BLAKE3_BLOCK_LEN - (size_t)self->buf_len; + if (take > input_len) { + take = input_len; + } + memcpy(self->buf + self->buf_len, input, take); + self->buf_len += (uint8_t)take; + return take; +} + +static uint8_t chunk_state_maybe_start_flag(const blake3_chunk_state *self) { + if (self->blocks_compressed == 0) { + return CHUNK_START; + } + return 0; +} + +static void chunk_state_update(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { + if (self->buf_len > 0) { + size_t take = chunk_state_fill_buf(self, input, input_len); + input += take; + input_len -= take; + if (input_len > 0) { + compress_in_place(self->cv, self->buf, BLAKE3_BLOCK_LEN, + self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); + self->blocks_compressed++; + self->buf_len = 0; + memset(self->buf, 0, BLAKE3_BLOCK_LEN); + } + } + + while (input_len > BLAKE3_BLOCK_LEN) { + compress_in_place(self->cv, input, BLAKE3_BLOCK_LEN, + self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); + self->blocks_compressed++; + input += BLAKE3_BLOCK_LEN; + input_len -= BLAKE3_BLOCK_LEN; + } + + size_t take = chunk_state_fill_buf(self, input, input_len); + (void)take; +} + +static void chunk_state_output(const blake3_chunk_state *self, uint8_t out[BLAKE3_OUT_LEN]) { + uint8_t block_flags = self->flags | chunk_state_maybe_start_flag(self) | CHUNK_END; + uint8_t wide_buf[64]; + compress_xof(self->cv, self->buf, self->buf_len, self->chunk_counter, block_flags, wide_buf); + memcpy(out, wide_buf, BLAKE3_OUT_LEN); +} + +// Hasher functions +void blake3_hasher_init(blake3_hasher *self) { + memcpy(self->key, IV, BLAKE3_KEY_LEN); + chunk_state_init(&self->chunk, IV, 0); + self->cv_stack_len = 0; +} + +void blake3_hasher_init_keyed(blake3_hasher *self, const uint8_t key[BLAKE3_KEY_LEN]) { + uint32_t key_words[8]; + for (size_t i = 0; i < 8; i++) { + key_words[i] = load32_le(key + 4 * i); + } + memcpy(self->key, key_words, BLAKE3_KEY_LEN); + chunk_state_init(&self->chunk, key_words, KEYED_HASH); + self->cv_stack_len = 0; +} + +void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context) { + blake3_hasher_init_derive_key_raw(self, context, strlen(context)); +} + +void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len) { + blake3_hasher context_hasher; + memcpy(context_hasher.key, IV, BLAKE3_KEY_LEN); + chunk_state_init(&context_hasher.chunk, IV, DERIVE_KEY_CONTEXT); + context_hasher.cv_stack_len = 0; + blake3_hasher_update(&context_hasher, context, context_len); + uint8_t context_key[BLAKE3_KEY_LEN]; + blake3_hasher_finalize(&context_hasher, context_key, BLAKE3_KEY_LEN); + uint32_t context_key_words[8]; + for (size_t i = 0; i < 8; i++) { + context_key_words[i] = load32_le(context_key + 4 * i); + } + memcpy(self->key, context_key_words, BLAKE3_KEY_LEN); + chunk_state_init(&self->chunk, context_key_words, DERIVE_KEY_MATERIAL); + self->cv_stack_len = 0; +} + +static void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) { + size_t post_merge_stack_len = (size_t)__builtin_popcountll(total_len); + while (self->cv_stack_len > post_merge_stack_len) { + uint8_t *parent_block = &self->cv_stack[(self->cv_stack_len - 2) * BLAKE3_OUT_LEN]; + uint32_t parent_cv[8]; + memcpy(parent_cv, self->key, BLAKE3_KEY_LEN); + compress_in_place(parent_cv, parent_block, BLAKE3_BLOCK_LEN, 0, self->chunk.flags | PARENT); + self->cv_stack_len--; + for (size_t i = 0; i < 8; i++) { + store32_le(&self->cv_stack[(self->cv_stack_len - 1) * BLAKE3_OUT_LEN + 4 * i], parent_cv[i]); + } + } +} + +static void hasher_push_cv(blake3_hasher *self, uint8_t new_cv[BLAKE3_OUT_LEN], uint64_t chunk_counter) { + hasher_merge_cv_stack(self, chunk_counter); + memcpy(&self->cv_stack[self->cv_stack_len * BLAKE3_OUT_LEN], new_cv, BLAKE3_OUT_LEN); + self->cv_stack_len++; +} + +void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len) { + const uint8_t *input_bytes = (const uint8_t *)input; + + while (input_len > 0) { + if (chunk_state_len(&self->chunk) == BLAKE3_CHUNK_LEN) { + uint8_t chunk_cv[32]; + chunk_state_output(&self->chunk, chunk_cv); + uint64_t total_chunks = self->chunk.chunk_counter + 1; + hasher_push_cv(self, chunk_cv, total_chunks); + chunk_state_init(&self->chunk, self->key, self->chunk.flags); + self->chunk.chunk_counter = total_chunks; + } + + size_t want = BLAKE3_CHUNK_LEN - chunk_state_len(&self->chunk); + size_t take = want < input_len ? want : input_len; + chunk_state_update(&self->chunk, input_bytes, take); + input_bytes += take; + input_len -= take; + } +} + +void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len) { + blake3_hasher_finalize_seek(self, 0, out, out_len); +} + +void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len) { + if (out_len == 0) { + return; + } + + // If the subtree stack is empty, the output is in the chunk state + if (self->cv_stack_len == 0) { + uint8_t block_flags = self->chunk.flags | chunk_state_maybe_start_flag(&self->chunk) | CHUNK_END | ROOT; + uint64_t output_block_counter = seek / 64; + size_t offset_within_block = seek % 64; + uint8_t wide_buf[64]; + compress_xof(self->chunk.cv, self->chunk.buf, self->chunk.buf_len, + output_block_counter, block_flags, wide_buf); + size_t available_bytes = 64 - offset_within_block; + size_t copy_len = out_len < available_bytes ? out_len : available_bytes; + memcpy(out, wide_buf + offset_within_block, copy_len); + out += copy_len; + out_len -= copy_len; + output_block_counter++; + + while (out_len > 0) { + compress_xof(self->chunk.cv, self->chunk.buf, self->chunk.buf_len, + output_block_counter, block_flags, wide_buf); + copy_len = out_len < 64 ? out_len : 64; + memcpy(out, wide_buf, copy_len); + out += copy_len; + out_len -= copy_len; + output_block_counter++; + } + return; + } + + // Otherwise merge the CV stack and finalize + uint8_t chunk_cv[32]; + chunk_state_output(&self->chunk, chunk_cv); + + uint8_t parent_block[BLAKE3_BLOCK_LEN]; + uint32_t parent_cv[8]; + size_t num_cvs = self->cv_stack_len; + memcpy(parent_block + BLAKE3_OUT_LEN, chunk_cv, BLAKE3_OUT_LEN); + + while (num_cvs > 0) { + memcpy(parent_block, &self->cv_stack[(num_cvs - 1) * BLAKE3_OUT_LEN], BLAKE3_OUT_LEN); + memcpy(parent_cv, self->key, BLAKE3_KEY_LEN); + uint8_t flags = self->chunk.flags | PARENT; + if (num_cvs == 1) { + flags |= ROOT; + } + compress_in_place(parent_cv, parent_block, BLAKE3_BLOCK_LEN, 0, flags); + num_cvs--; + for (size_t i = 0; i < 8; i++) { + store32_le(&parent_block[BLAKE3_OUT_LEN + 4 * i], parent_cv[i]); + } + } + + memcpy(out, parent_block + BLAKE3_OUT_LEN, out_len < BLAKE3_OUT_LEN ? out_len : BLAKE3_OUT_LEN); +} + +void blake3_hasher_reset(blake3_hasher *self) { + chunk_state_init(&self->chunk, self->key, self->chunk.flags & (KEYED_HASH | DERIVE_KEY_MATERIAL)); + self->cv_stack_len = 0; +} + +// Simple one-shot hash for mining +void blake3_hash(const void *input, size_t input_len, uint8_t out[BLAKE3_OUT_LEN]) { + blake3_hasher hasher; + blake3_hasher_init(&hasher); + blake3_hasher_update(&hasher, input, input_len); + blake3_hasher_finalize(&hasher, out, BLAKE3_OUT_LEN); +} diff --git a/miner/core/src/3rdparty/blake3/blake3.h b/miner/core/src/3rdparty/blake3/blake3.h new file mode 100644 index 0000000..0812aa1 --- /dev/null +++ b/miner/core/src/3rdparty/blake3/blake3.h @@ -0,0 +1,86 @@ +/* + * BLAKE3 reference implementation + * Based on https://github.com/BLAKE3-team/BLAKE3 + * + * This is a minimal implementation for Decred mining. + * For optimal performance, consider using SIMD-accelerated versions. + */ + +#ifndef BLAKE3_H +#define BLAKE3_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLAKE3_VERSION_STRING "1.8.2" +#define BLAKE3_KEY_LEN 32 +#define BLAKE3_OUT_LEN 32 +#define BLAKE3_BLOCK_LEN 64 +#define BLAKE3_CHUNK_LEN 1024 +#define BLAKE3_MAX_DEPTH 54 + +// Initial vector (same as BLAKE2s) +#define BLAKE3_IV_0 0x6A09E667UL +#define BLAKE3_IV_1 0xBB67AE85UL +#define BLAKE3_IV_2 0x3C6EF372UL +#define BLAKE3_IV_3 0xA54FF53AUL +#define BLAKE3_IV_4 0x510E527FUL +#define BLAKE3_IV_5 0x9B05688CUL +#define BLAKE3_IV_6 0x1F83D9ABUL +#define BLAKE3_IV_7 0x5BE0CD19UL + +// Flags for domain separation +enum blake3_flags { + CHUNK_START = 1 << 0, + CHUNK_END = 1 << 1, + PARENT = 1 << 2, + ROOT = 1 << 3, + KEYED_HASH = 1 << 4, + DERIVE_KEY_CONTEXT = 1 << 5, + DERIVE_KEY_MATERIAL = 1 << 6, +}; + +typedef struct { + uint32_t cv[8]; + uint64_t chunk_counter; + uint8_t buf[BLAKE3_BLOCK_LEN]; + uint8_t buf_len; + uint8_t blocks_compressed; + uint8_t flags; +} blake3_chunk_state; + +typedef struct { + uint32_t key[8]; + blake3_chunk_state chunk; + uint8_t cv_stack_len; + uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN]; +} blake3_hasher; + +// Initialize hasher +void blake3_hasher_init(blake3_hasher *self); +void blake3_hasher_init_keyed(blake3_hasher *self, const uint8_t key[BLAKE3_KEY_LEN]); +void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context); +void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len); + +// Update with input data +void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len); + +// Finalize and output +void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len); +void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); + +// Reset hasher for reuse +void blake3_hasher_reset(blake3_hasher *self); + +// Simple one-shot hash function for mining +void blake3_hash(const void *input, size_t input_len, uint8_t out[BLAKE3_OUT_LEN]); + +#ifdef __cplusplus +} +#endif + +#endif // BLAKE3_H diff --git a/miner/core/src/base/crypto/Algorithm.cpp b/miner/core/src/base/crypto/Algorithm.cpp index 543434f..b63b7f6 100644 --- a/miner/core/src/base/crypto/Algorithm.cpp +++ b/miner/core/src/base/crypto/Algorithm.cpp @@ -113,6 +113,11 @@ const char *Algorithm::kPROGPOWZ = "progpowz"; const char *Algorithm::kPROGPOWZ_ZANO = "progpowz"; #endif +#ifdef XMRIG_ALGO_BLAKE3DCR +const char *Algorithm::kBLAKE3 = "blake3"; +const char *Algorithm::kBLAKE3_DCR = "blake3"; +#endif + #define ALGO_NAME(ALGO) { Algorithm::ALGO, Algorithm::k##ALGO } #define ALGO_ALIAS(ALGO, NAME) { NAME, Algorithm::ALGO } @@ -184,6 +189,10 @@ static const std::map kAlgorithmNames = { # ifdef XMRIG_ALGO_PROGPOWZ ALGO_NAME(PROGPOWZ_ZANO), # endif + +# ifdef XMRIG_ALGO_BLAKE3DCR + ALGO_NAME(BLAKE3_DCR), +# endif }; @@ -313,6 +322,12 @@ static const std::map kAlgorithmAlias ALGO_ALIAS_AUTO(PROGPOWZ_ZANO), ALGO_ALIAS(PROGPOWZ_ZANO, "progpowz/zano"), ALGO_ALIAS(PROGPOWZ_ZANO, "zano"), # endif + +# ifdef XMRIG_ALGO_BLAKE3DCR + ALGO_ALIAS_AUTO(BLAKE3_DCR), ALGO_ALIAS(BLAKE3_DCR, "blake3/dcr"), + ALGO_ALIAS(BLAKE3_DCR, "dcr"), + ALGO_ALIAS(BLAKE3_DCR, "decred"), +# endif }; @@ -389,7 +404,8 @@ std::vector xmrig::Algorithm::all(const std::function. + */ + + +#include "crypto/blake3dcr/Blake3DCR.h" +#include "3rdparty/blake3/blake3.h" + +#include + + +namespace xmrig { + + +void Blake3DCR::hash(const uint8_t* header, size_t header_len, uint8_t* output) +{ + blake3_hash(header, header_len, output); +} + + +void Blake3DCR::calculate(const uint8_t* header, uint32_t nonce, uint8_t (&output)[32]) +{ + // Copy header and insert nonce at the correct offset + uint8_t work[BLOCK_HEADER_SIZE]; + memcpy(work, header, BLOCK_HEADER_SIZE); + + // Insert nonce (little-endian) at offset 140 + work[NONCE_OFFSET] = static_cast(nonce); + work[NONCE_OFFSET + 1] = static_cast(nonce >> 8); + work[NONCE_OFFSET + 2] = static_cast(nonce >> 16); + work[NONCE_OFFSET + 3] = static_cast(nonce >> 24); + + // Calculate Blake3 hash + blake3_hash(work, BLOCK_HEADER_SIZE, output); +} + + +bool Blake3DCR::checkDifficulty(const uint8_t* hash, const uint8_t* target) +{ + // Compare hash with target (both are big-endian 256-bit numbers) + // Hash must be less than or equal to target + for (int i = 0; i < 32; i++) { + if (hash[i] < target[i]) { + return true; + } + if (hash[i] > target[i]) { + return false; + } + } + return true; +} + + +} // namespace xmrig diff --git a/miner/core/src/crypto/blake3dcr/Blake3DCR.h b/miner/core/src/crypto/blake3dcr/Blake3DCR.h new file mode 100644 index 0000000..7abc1a3 --- /dev/null +++ b/miner/core/src/crypto/blake3dcr/Blake3DCR.h @@ -0,0 +1,55 @@ +/* Miner + * Copyright (c) 2025 Lethean + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_BLAKE3DCR_H +#define XMRIG_BLAKE3DCR_H + + +#include +#include + + +namespace xmrig +{ + + +class Blake3DCR +{ +public: + // Blake3DCR constants for Decred mining + // Decred block header is 180 bytes + static constexpr size_t BLOCK_HEADER_SIZE = 180; + static constexpr size_t HASH_SIZE = 32; + + // Nonce position in Decred block header (bytes 140-143) + static constexpr size_t NONCE_OFFSET = 140; + + // Calculate Blake3 hash of block header + static void hash(const uint8_t* header, size_t header_len, uint8_t* output); + + // Mining function: tries nonce and returns hash + static void calculate(const uint8_t* header, uint32_t nonce, uint8_t (&output)[32]); + + // Check if hash meets difficulty target + static bool checkDifficulty(const uint8_t* hash, const uint8_t* target); +}; + + +} // namespace xmrig + + +#endif // XMRIG_BLAKE3DCR_H