From ef320a439731b9cd302680976334bc437cd80f7e Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Mon, 30 Mar 2026 09:05:06 +0200 Subject: [PATCH] perf(miner): route nonce scanning through sha256d80_scan_4way --- miner.c | 145 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/miner.c b/miner.c index 5adca91..33ba944 100644 --- a/miner.c +++ b/miner.c @@ -1,99 +1,103 @@ #include "miner.h" -#include #include #include #include #include +#include "sha256/sha256_backend.h" #include "utils.h" static const double RATE_INTERVAL_SEC = 5.0; -static int hash_meets_target(const uint8_t digest[32], const uint8_t target_be[32]) { - int i; - - for (i = 0; i < 32; i++) { - uint8_t hb = digest[31 - i]; - if (hb < target_be[i]) { - return 1; - } - if (hb > target_be[i]) { - return 0; - } - } - - return 1; +static inline uint32_t load_u32_be(const uint8_t *p) { + return ((uint32_t)p[0] << 24) | + ((uint32_t)p[1] << 16) | + ((uint32_t)p[2] << 8) | + (uint32_t)p[3]; } -static void write_u32_be(uint8_t *dst, uint32_t v) { - dst[0] = (uint8_t)((v >> 24) & 0xFF); - dst[1] = (uint8_t)((v >> 16) & 0xFF); - dst[2] = (uint8_t)((v >> 8) & 0xFF); - dst[3] = (uint8_t)(v & 0xFF); -} - -static void sha256_ctx_to_digest(const SHA256_CTX *ctx, uint8_t out[32]) { +static void target_words_from_be(const uint8_t target_be[32], uint32_t out[8]) { int i; for (i = 0; i < 8; i++) { - write_u32_be(out + i * 4, ctx->h[i]); + out[i] = load_u32_be(target_be + i * 4); } } +static inline void write_u32_le(uint8_t *dst, uint32_t v) { + dst[0] = (uint8_t)(v & 0xFFU); + dst[1] = (uint8_t)((v >> 8) & 0xFFU); + dst[2] = (uint8_t)((v >> 16) & 0xFFU); + dst[3] = (uint8_t)((v >> 24) & 0xFFU); +} + static int compute_hash_batch( const uint8_t header_76[76], uint32_t start_nonce, uint32_t batch_size, - const uint8_t target_be[32], + const uint32_t target_words[8], uint32_t *found_nonce, uint8_t found_digest[32] ) { - SHA256_CTX init_ctx; - SHA256_CTX first_chunk_ctx; - uint8_t block1[64]; - uint8_t block2[64]; - uint8_t digest1[32]; - uint8_t digest2[32]; - uint32_t i; + sha256d80_midstate_t mid; + uint32_t i = 0; + sha256d80_midstate_init(&mid, header_76); - SHA256_Init(&init_ctx); - first_chunk_ctx = init_ctx; - SHA256_Transform(&first_chunk_ctx, header_76); + while ((batch_size - i) >= 4U) { + uint32_t n0 = start_nonce + i; + sha256_state_t st1[4]; + uint32_t mask = sha256d80_scan_4way(&mid, n0, target_words, st1); - memset(block1, 0, sizeof(block1)); - memcpy(block1, header_76 + 64, 12); - block1[16] = 0x80; - block1[62] = 0x02; - block1[63] = 0x80; + if (mask & 1U) { + *found_nonce = n0; + sha256_state_to_digest(&st1[0], found_digest); + return 1; + } + if (mask & 2U) { + *found_nonce = n0 + 1U; + sha256_state_to_digest(&st1[1], found_digest); + return 1; + } + if (mask & 4U) { + *found_nonce = n0 + 2U; + sha256_state_to_digest(&st1[2], found_digest); + return 1; + } + if (mask & 8U) { + *found_nonce = n0 + 3U; + sha256_state_to_digest(&st1[3], found_digest); + return 1; + } - memset(block2, 0, sizeof(block2)); - block2[32] = 0x80; - block2[62] = 0x01; - block2[63] = 0x00; + i += 4U; + } - for (i = 0; i < batch_size; i++) { - SHA256_CTX ctx1; - SHA256_CTX ctx2; - uint32_t n = start_nonce + i; + if (i < batch_size) { + uint32_t n0 = start_nonce + i; + uint32_t remain = batch_size - i; + uint32_t valid_mask = (1U << remain) - 1U; + sha256_state_t st1[4]; + uint32_t mask = sha256d80_scan_4way(&mid, n0, target_words, st1) & valid_mask; - block1[12] = (uint8_t)(n & 0xFF); - block1[13] = (uint8_t)((n >> 8) & 0xFF); - block1[14] = (uint8_t)((n >> 16) & 0xFF); - block1[15] = (uint8_t)((n >> 24) & 0xFF); - - ctx1 = first_chunk_ctx; - SHA256_Transform(&ctx1, block1); - sha256_ctx_to_digest(&ctx1, digest1); - - memcpy(block2, digest1, 32); - ctx2 = init_ctx; - SHA256_Transform(&ctx2, block2); - sha256_ctx_to_digest(&ctx2, digest2); - - if (hash_meets_target(digest2, target_be)) { - *found_nonce = n; - memcpy(found_digest, digest2, 32); + if (mask & 1U) { + *found_nonce = n0; + sha256_state_to_digest(&st1[0], found_digest); + return 1; + } + if (mask & 2U) { + *found_nonce = n0 + 1U; + sha256_state_to_digest(&st1[1], found_digest); + return 1; + } + if (mask & 4U) { + *found_nonce = n0 + 2U; + sha256_state_to_digest(&st1[2], found_digest); + return 1; + } + if (mask & 8U) { + *found_nonce = n0 + 3U; + sha256_state_to_digest(&st1[3], found_digest); return 1; } } @@ -101,13 +105,6 @@ static int compute_hash_batch( return 0; } -static void write_u32_le(uint8_t *dst, uint32_t v) { - dst[0] = (uint8_t)(v & 0xFF); - dst[1] = (uint8_t)((v >> 8) & 0xFF); - dst[2] = (uint8_t)((v >> 16) & 0xFF); - dst[3] = (uint8_t)((v >> 24) & 0xFF); -} - int mine_block( uint8_t header_76[76], const char *target_hex, @@ -120,6 +117,7 @@ int mine_block( MineResult *out ) { uint8_t target_be[32]; + uint32_t target_words[8]; uint32_t nonce; long long attempts = 0; time_t t_start; @@ -133,6 +131,7 @@ int mine_block( fprintf(stderr, "[miner] target hex non valido\n"); return 0; } + target_words_from_be(target_be, target_words); if (strcmp(nonce_mode, "incremental") == 0) { nonce = 0; @@ -162,7 +161,7 @@ int mine_block( last_tsu = now; } - if (compute_hash_batch(header_76, nonce, batch_size, target_be, &found_nonce, found_digest)) { + if (compute_hash_batch(header_76, nonce, batch_size, target_words, &found_nonce, found_digest)) { double total = now - (double)t_start; if (total <= 0.0) { total = 1e-6;