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:
parent
b7af288374
commit
9cf0db802a
9 changed files with 609 additions and 3 deletions
|
|
@ -11,6 +11,7 @@ option(WITH_ARGON2 "Enable Argon2 algorithms family" ON)
|
||||||
option(WITH_KAWPOW "Enable KawPow algorithms family" ON)
|
option(WITH_KAWPOW "Enable KawPow algorithms family" ON)
|
||||||
option(WITH_ETCHASH "Enable ETChash/Ethash algorithms family" ON)
|
option(WITH_ETCHASH "Enable ETChash/Ethash algorithms family" ON)
|
||||||
option(WITH_PROGPOWZ "Enable ProgPowZ algorithm (Zano)" 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_GHOSTRIDER "Enable GhostRider algorithm" ON)
|
||||||
option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON)
|
option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON)
|
||||||
option(WITH_DEBUG_LOG "Enable debug log output" OFF)
|
option(WITH_DEBUG_LOG "Enable debug log output" OFF)
|
||||||
|
|
@ -205,6 +206,7 @@ include(cmake/argon2.cmake)
|
||||||
include(cmake/kawpow.cmake)
|
include(cmake/kawpow.cmake)
|
||||||
include(cmake/etchash.cmake)
|
include(cmake/etchash.cmake)
|
||||||
include(cmake/progpowz.cmake)
|
include(cmake/progpowz.cmake)
|
||||||
|
include(cmake/blake3dcr.cmake)
|
||||||
include(cmake/ghostrider.cmake)
|
include(cmake/ghostrider.cmake)
|
||||||
include(cmake/OpenSSL.cmake)
|
include(cmake/OpenSSL.cmake)
|
||||||
include(cmake/asm.cmake)
|
include(cmake/asm.cmake)
|
||||||
|
|
@ -241,7 +243,7 @@ if (WITH_DEBUG_LOG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${TLS_SOURCES} ${XMRIG_ASM_SOURCES})
|
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 (WIN32)
|
||||||
if (NOT ARM_TARGET)
|
if (NOT ARM_TARGET)
|
||||||
|
|
|
||||||
17
miner/core/cmake/blake3dcr.cmake
Normal file
17
miner/core/cmake/blake3dcr.cmake
Normal 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()
|
||||||
14
miner/core/src/3rdparty/blake3/CMakeLists.txt
vendored
Normal file
14
miner/core/src/3rdparty/blake3/CMakeLists.txt
vendored
Normal 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
342
miner/core/src/3rdparty/blake3/blake3.c
vendored
Normal 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
86
miner/core/src/3rdparty/blake3/blake3.h
vendored
Normal 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
|
||||||
|
|
@ -113,6 +113,11 @@ const char *Algorithm::kPROGPOWZ = "progpowz";
|
||||||
const char *Algorithm::kPROGPOWZ_ZANO = "progpowz";
|
const char *Algorithm::kPROGPOWZ_ZANO = "progpowz";
|
||||||
#endif
|
#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_NAME(ALGO) { Algorithm::ALGO, Algorithm::k##ALGO }
|
||||||
#define ALGO_ALIAS(ALGO, NAME) { NAME, Algorithm::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
|
# ifdef XMRIG_ALGO_PROGPOWZ
|
||||||
ALGO_NAME(PROGPOWZ_ZANO),
|
ALGO_NAME(PROGPOWZ_ZANO),
|
||||||
# endif
|
# 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_AUTO(PROGPOWZ_ZANO), ALGO_ALIAS(PROGPOWZ_ZANO, "progpowz/zano"),
|
||||||
ALGO_ALIAS(PROGPOWZ_ZANO, "zano"),
|
ALGO_ALIAS(PROGPOWZ_ZANO, "zano"),
|
||||||
# endif
|
# 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,
|
KAWPOW_RVN,
|
||||||
GHOSTRIDER_RTM,
|
GHOSTRIDER_RTM,
|
||||||
ETCHASH_ETC, ETHASH_ETH,
|
ETCHASH_ETC, ETHASH_ETH,
|
||||||
PROGPOWZ_ZANO
|
PROGPOWZ_ZANO,
|
||||||
|
BLAKE3_DCR
|
||||||
};
|
};
|
||||||
|
|
||||||
Algorithms out;
|
Algorithms out;
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ public:
|
||||||
ETCHASH_ETC = 0x65100000, // "etchash" ETChash (ETC)
|
ETCHASH_ETC = 0x65100000, // "etchash" ETChash (ETC)
|
||||||
ETHASH_ETH = 0x65100001, // "ethash" Ethash (ETH)
|
ETHASH_ETH = 0x65100001, // "ethash" Ethash (ETH)
|
||||||
PROGPOWZ_ZANO = 0x70100000, // "progpowz" ProgPowZ (ZANO)
|
PROGPOWZ_ZANO = 0x70100000, // "progpowz" ProgPowZ (ZANO)
|
||||||
|
BLAKE3_DCR = 0x62100000, // "blake3" Blake3 (DCR)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Family : uint32_t {
|
enum Family : uint32_t {
|
||||||
|
|
@ -100,7 +101,8 @@ public:
|
||||||
KAWPOW = 0x6b000000,
|
KAWPOW = 0x6b000000,
|
||||||
GHOSTRIDER = 0x6c000000,
|
GHOSTRIDER = 0x6c000000,
|
||||||
ETCHASH = 0x65000000,
|
ETCHASH = 0x65000000,
|
||||||
PROGPOWZ = 0x70000000
|
PROGPOWZ = 0x70000000,
|
||||||
|
BLAKE3 = 0x62000000
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *kINVALID;
|
static const char *kINVALID;
|
||||||
|
|
@ -180,6 +182,11 @@ public:
|
||||||
static const char *kPROGPOWZ_ZANO;
|
static const char *kPROGPOWZ_ZANO;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
# ifdef XMRIG_ALGO_BLAKE3DCR
|
||||||
|
static const char *kBLAKE3;
|
||||||
|
static const char *kBLAKE3_DCR;
|
||||||
|
# endif
|
||||||
|
|
||||||
inline Algorithm() = default;
|
inline Algorithm() = default;
|
||||||
inline Algorithm(const char *algo) : m_id(parse(algo)) {}
|
inline Algorithm(const char *algo) : m_id(parse(algo)) {}
|
||||||
inline Algorithm(Id id) : m_id(id) {}
|
inline Algorithm(Id id) : m_id(id) {}
|
||||||
|
|
|
||||||
67
miner/core/src/crypto/blake3dcr/Blake3DCR.cpp
Normal file
67
miner/core/src/crypto/blake3dcr/Blake3DCR.cpp
Normal 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
|
||||||
55
miner/core/src/crypto/blake3dcr/Blake3DCR.h
Normal file
55
miner/core/src/crypto/blake3dcr/Blake3DCR.h
Normal 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
|
||||||
Loading…
Add table
Reference in a new issue