feat: Add Blake3DCR algorithm support (Decred)

- Add Blake3 cryptographic hash library (portable C implementation)
- Create Blake3DCR wrapper for Decred mining (180-byte block headers)
- Register BLAKE3_DCR algorithm ID (0x62100000) with dcr/decred aliases
- Support for block header hashing and nonce iteration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
snider 2025-12-30 20:30:05 +00:00
parent b7af288374
commit 9cf0db802a
9 changed files with 609 additions and 3 deletions

View file

@ -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)

View file

@ -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()

View file

@ -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})

342
miner/core/src/3rdparty/blake3/blake3.c vendored Normal file
View file

@ -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 <string.h>
// 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);
}

86
miner/core/src/3rdparty/blake3/blake3.h vendored Normal file
View file

@ -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 <stddef.h>
#include <stdint.h>
#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

View file

@ -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<uint32_t, const char *> 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<const char *, Algorithm::Id, aliasCompare> 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> xmrig::Algorithm::all(const std::function<bool(con
KAWPOW_RVN,
GHOSTRIDER_RTM,
ETCHASH_ETC, ETHASH_ETH,
PROGPOWZ_ZANO
PROGPOWZ_ZANO,
BLAKE3_DCR
};
Algorithms out;

View file

@ -85,6 +85,7 @@ public:
ETCHASH_ETC = 0x65100000, // "etchash" ETChash (ETC)
ETHASH_ETH = 0x65100001, // "ethash" Ethash (ETH)
PROGPOWZ_ZANO = 0x70100000, // "progpowz" ProgPowZ (ZANO)
BLAKE3_DCR = 0x62100000, // "blake3" Blake3 (DCR)
};
enum Family : uint32_t {
@ -100,7 +101,8 @@ public:
KAWPOW = 0x6b000000,
GHOSTRIDER = 0x6c000000,
ETCHASH = 0x65000000,
PROGPOWZ = 0x70000000
PROGPOWZ = 0x70000000,
BLAKE3 = 0x62000000
};
static const char *kINVALID;
@ -180,6 +182,11 @@ public:
static const char *kPROGPOWZ_ZANO;
# endif
# ifdef XMRIG_ALGO_BLAKE3DCR
static const char *kBLAKE3;
static const char *kBLAKE3_DCR;
# endif
inline Algorithm() = default;
inline Algorithm(const char *algo) : m_id(parse(algo)) {}
inline Algorithm(Id id) : m_id(id) {}

View file

@ -0,0 +1,67 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#include "crypto/blake3dcr/Blake3DCR.h"
#include "3rdparty/blake3/blake3.h"
#include <cstring>
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<uint8_t>(nonce);
work[NONCE_OFFSET + 1] = static_cast<uint8_t>(nonce >> 8);
work[NONCE_OFFSET + 2] = static_cast<uint8_t>(nonce >> 16);
work[NONCE_OFFSET + 3] = static_cast<uint8_t>(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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_BLAKE3DCR_H
#define XMRIG_BLAKE3DCR_H
#include <cstdint>
#include <cstddef>
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