549 lines
12 KiB
C
549 lines
12 KiB
C
//
|
|
// Arquiteturas de Alto Desempenho 2025/2026
|
|
//
|
|
// DETI Coin Miner - WebAssembly implementation with SIMD support
|
|
//
|
|
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "aad_data_types.h"
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
#include <emscripten.h>
|
|
#include "aad_sha1_wasm.h"
|
|
#else
|
|
#include "aad_sha1_cpu.h"
|
|
#include "aad_utilities.h"
|
|
#include "aad_vault.h"
|
|
#endif
|
|
|
|
// WASM SIMD support
|
|
#if defined(__wasm_simd128__)
|
|
#include <wasm_simd128.h>
|
|
#endif
|
|
|
|
// Global mining state
|
|
static volatile int keep_running = 1;
|
|
static volatile int use_simd = 0;
|
|
static u64_t total_attempts = 0;
|
|
static u32_t coins_found = 0;
|
|
static double mining_start_time = 0;
|
|
static double pause_time_offset = 0;
|
|
static double last_pause_time = 0;
|
|
static u32_t found_coins[1024][14];
|
|
static u32_t found_coins_count = 0;
|
|
|
|
//
|
|
// Check if a hash starts with aad20250
|
|
//
|
|
static int is_valid_coin(u32_t *hash)
|
|
{
|
|
return hash[0] == 0xAAD20250u;
|
|
}
|
|
|
|
//
|
|
// Increment coin variable part (positions 12-53)
|
|
//
|
|
static int increment_coin(u32_t coin[14])
|
|
{
|
|
int pos = 53;
|
|
while(pos >= 12)
|
|
{
|
|
u08_t *byte = &((u08_t *)coin)[pos ^ 3];
|
|
if(*byte == '\n' || *byte == 0x80)
|
|
*byte = 32;
|
|
|
|
(*byte)++;
|
|
|
|
if(*byte == '\n')
|
|
(*byte)++;
|
|
|
|
if(*byte >= 127)
|
|
{
|
|
*byte = 32;
|
|
pos--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (pos >= 12);
|
|
}
|
|
|
|
//
|
|
// Get current time in seconds
|
|
//
|
|
static double get_time()
|
|
{
|
|
#ifdef __EMSCRIPTEN__
|
|
return emscripten_get_now() / 1000.0;
|
|
#else
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
|
return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
|
|
#endif
|
|
}
|
|
|
|
#if defined(__wasm_simd128__)
|
|
//
|
|
// Helper macro for Left Rotate (ROTL) using SIMD shifts
|
|
// CORRECTION: Used wasm_u32x4_shr instead of incorrect wasm_i32x4_shr_u
|
|
//
|
|
#define SIMD_ROTL(x, n) wasm_v128_or(wasm_i32x4_shl(x, n), wasm_u32x4_shr(x, 32 - n))
|
|
|
|
//
|
|
// SIMD implementation for WebAssembly (4-way parallel)
|
|
//
|
|
static void prepare_coins_simd(u32_t base_coin[14], u32_t *interleaved_data)
|
|
{
|
|
const int SIMD_WIDTH = 4;
|
|
for(int lane = 0; lane < SIMD_WIDTH; lane++)
|
|
{
|
|
u32_t coin[14];
|
|
memcpy(coin, base_coin, sizeof(coin));
|
|
|
|
for(int idx = 0; idx < 14; idx++)
|
|
{
|
|
interleaved_data[idx * SIMD_WIDTH + lane] = coin[idx];
|
|
}
|
|
|
|
increment_coin(base_coin);
|
|
}
|
|
}
|
|
|
|
static void extract_hashes_simd(u32_t *interleaved_hash, u32_t hashes[][5])
|
|
{
|
|
const int SIMD_WIDTH = 4;
|
|
for(int lane = 0; lane < SIMD_WIDTH; lane++)
|
|
{
|
|
for(int idx = 0; idx < 5; idx++)
|
|
{
|
|
hashes[lane][idx] = interleaved_hash[idx * SIMD_WIDTH + lane];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void extract_coins_simd(u32_t *interleaved_data, u32_t coins[][14])
|
|
{
|
|
const int SIMD_WIDTH = 4;
|
|
for(int lane = 0; lane < SIMD_WIDTH; lane++)
|
|
{
|
|
for(int idx = 0; idx < 14; idx++)
|
|
{
|
|
coins[lane][idx] = interleaved_data[idx * SIMD_WIDTH + lane];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sha1_wasm_simd(u32_t *interleaved_data, u32_t *interleaved_hash)
|
|
{
|
|
const int SIMD_WIDTH = 4;
|
|
|
|
// SHA1 State vectors
|
|
v128_t a, b, c, d, e;
|
|
v128_t w[80]; // Message schedule
|
|
|
|
// Initial SHA1 constants
|
|
a = wasm_i32x4_splat(0x67452301u);
|
|
b = wasm_i32x4_splat(0xEFCDAB89u);
|
|
c = wasm_i32x4_splat(0x98BADCFEu);
|
|
d = wasm_i32x4_splat(0x10325476u);
|
|
e = wasm_i32x4_splat(0xC3D2E1F0u);
|
|
|
|
// 1. Prepare Message Schedule (Interleaved loads)
|
|
// Load first 14 words
|
|
for(int i = 0; i < 14; i++)
|
|
{
|
|
w[i] = wasm_v128_load(&interleaved_data[i * SIMD_WIDTH]);
|
|
}
|
|
// Standard padding (assumed handled by caller/init)
|
|
w[14] = wasm_i32x4_splat(0);
|
|
w[15] = wasm_i32x4_splat(440); // Length in bits (55 bytes * 8)
|
|
|
|
// Expand message schedule from 16 to 80
|
|
for (int i = 16; i < 80; i++) {
|
|
v128_t temp = wasm_v128_xor(w[i-3], w[i-8]);
|
|
temp = wasm_v128_xor(temp, w[i-14]);
|
|
temp = wasm_v128_xor(temp, w[i-16]);
|
|
w[i] = SIMD_ROTL(temp, 1);
|
|
}
|
|
|
|
// 2. Main Loop (80 rounds)
|
|
for (int i = 0; i < 80; i++) {
|
|
v128_t f, k;
|
|
|
|
if (i < 20) {
|
|
// F1: (b & c) | (~b & d)
|
|
f = wasm_v128_or(wasm_v128_and(b, c), wasm_v128_and(wasm_v128_not(b), d));
|
|
k = wasm_i32x4_splat(0x5A827999u);
|
|
} else if (i < 40) {
|
|
// F2: b ^ c ^ d
|
|
f = wasm_v128_xor(wasm_v128_xor(b, c), d);
|
|
k = wasm_i32x4_splat(0x6ED9EBA1u);
|
|
} else if (i < 60) {
|
|
// F3: (b & c) | (b & d) | (c & d)
|
|
f = wasm_v128_or(wasm_v128_or(wasm_v128_and(b, c), wasm_v128_and(b, d)), wasm_v128_and(c, d));
|
|
k = wasm_i32x4_splat(0x8F1BBCDCu);
|
|
} else {
|
|
// F4: b ^ c ^ d
|
|
f = wasm_v128_xor(wasm_v128_xor(b, c), d);
|
|
k = wasm_i32x4_splat(0xCA62C1D6u);
|
|
}
|
|
|
|
// temp = ROTL(a, 5) + f + e + k + w[i]
|
|
v128_t temp = wasm_i32x4_add(SIMD_ROTL(a, 5), f);
|
|
temp = wasm_i32x4_add(temp, e);
|
|
temp = wasm_i32x4_add(temp, k);
|
|
temp = wasm_i32x4_add(temp, w[i]);
|
|
|
|
e = d;
|
|
d = c;
|
|
c = SIMD_ROTL(b, 30);
|
|
b = a;
|
|
a = temp;
|
|
}
|
|
|
|
// 3. Add to initial state and store
|
|
v128_t h0 = wasm_i32x4_add(a, wasm_i32x4_splat(0x67452301u));
|
|
v128_t h1 = wasm_i32x4_add(b, wasm_i32x4_splat(0xEFCDAB89u));
|
|
v128_t h2 = wasm_i32x4_add(c, wasm_i32x4_splat(0x98BADCFEu));
|
|
v128_t h3 = wasm_i32x4_add(d, wasm_i32x4_splat(0x10325476u));
|
|
v128_t h4 = wasm_i32x4_add(e, wasm_i32x4_splat(0xC3D2E1F0u));
|
|
|
|
// Store results back to interleaved_hash
|
|
wasm_v128_store(&interleaved_hash[0 * SIMD_WIDTH], h0);
|
|
wasm_v128_store(&interleaved_hash[1 * SIMD_WIDTH], h1);
|
|
wasm_v128_store(&interleaved_hash[2 * SIMD_WIDTH], h2);
|
|
wasm_v128_store(&interleaved_hash[3 * SIMD_WIDTH], h3);
|
|
wasm_v128_store(&interleaved_hash[4 * SIMD_WIDTH], h4);
|
|
}
|
|
|
|
static int mine_coins_wasm_simd_internal(u32_t iterations_per_call, u32_t coin[14])
|
|
{
|
|
const int SIMD_WIDTH = 4;
|
|
u32_t interleaved_data[14 * SIMD_WIDTH] __attribute__((aligned(16)));
|
|
u32_t interleaved_hash[5 * SIMD_WIDTH] __attribute__((aligned(16)));
|
|
|
|
u32_t batches = (iterations_per_call + SIMD_WIDTH - 1) / SIMD_WIDTH;
|
|
|
|
for(u32_t batch = 0; batch < batches && keep_running; batch++)
|
|
{
|
|
prepare_coins_simd(coin, interleaved_data);
|
|
|
|
// This now uses the REAL vectorized implementation
|
|
sha1_wasm_simd(interleaved_data, interleaved_hash);
|
|
|
|
total_attempts += SIMD_WIDTH;
|
|
|
|
u32_t hashes[SIMD_WIDTH][5];
|
|
extract_hashes_simd(interleaved_hash, hashes);
|
|
|
|
for(int lane = 0; lane < SIMD_WIDTH; lane++)
|
|
{
|
|
if(is_valid_coin(hashes[lane]))
|
|
{
|
|
if(found_coins_count < 1024)
|
|
{
|
|
u32_t coins[SIMD_WIDTH][14];
|
|
extract_coins_simd(interleaved_data, coins);
|
|
memcpy(found_coins[found_coins_count], coins[lane], sizeof(coins[lane]));
|
|
found_coins_count++;
|
|
}
|
|
coins_found++;
|
|
|
|
#ifndef __EMSCRIPTEN__
|
|
printf("COIN FOUND! (attempt %llu, lane %d)\n",
|
|
(unsigned long long)(total_attempts - SIMD_WIDTH + lane), lane);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
return keep_running;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Main mining iteration (called from JavaScript)
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
int mine_coins_wasm(u32_t iterations_per_call)
|
|
{
|
|
static u32_t coin[14];
|
|
static int initialized = 0;
|
|
static int last_logged_mode = -1; // Track last reported mode
|
|
|
|
u32_t hash[5];
|
|
|
|
// Initialize coin template on first call
|
|
if(!initialized)
|
|
{
|
|
memset(coin, 0, sizeof(coin));
|
|
((u08_t *)coin)[0x0 ^ 3] = 'D';
|
|
((u08_t *)coin)[0x1 ^ 3] = 'E';
|
|
((u08_t *)coin)[0x2 ^ 3] = 'T';
|
|
((u08_t *)coin)[0x3 ^ 3] = 'I';
|
|
((u08_t *)coin)[0x4 ^ 3] = ' ';
|
|
((u08_t *)coin)[0x5 ^ 3] = 'c';
|
|
((u08_t *)coin)[0x6 ^ 3] = 'o';
|
|
((u08_t *)coin)[0x7 ^ 3] = 'i';
|
|
((u08_t *)coin)[0x8 ^ 3] = 'n';
|
|
((u08_t *)coin)[0x9 ^ 3] = ' ';
|
|
((u08_t *)coin)[0xa ^ 3] = '2';
|
|
((u08_t *)coin)[0xb ^ 3] = ' ';
|
|
((u08_t *)coin)[0x36 ^ 3] = '\n';
|
|
((u08_t *)coin)[0x37 ^ 3] = 0x80;
|
|
|
|
for(int i = 12; i < 54; i++)
|
|
((u08_t *)coin)[i ^ 3] = 'A' + (i - 12) % 26;
|
|
|
|
mining_start_time = get_time();
|
|
initialized = 1;
|
|
}
|
|
|
|
if(!keep_running)
|
|
return 0;
|
|
|
|
#if defined(__wasm_simd128__)
|
|
if(use_simd)
|
|
{
|
|
if (last_logged_mode != 1) {
|
|
printf("C: Running in SIMD Mode (Vectorized)\n");
|
|
last_logged_mode = 1;
|
|
}
|
|
return mine_coins_wasm_simd_internal(iterations_per_call, coin);
|
|
}
|
|
#endif
|
|
|
|
if (last_logged_mode != 0) {
|
|
printf("C: Running in Scalar Mode\n");
|
|
last_logged_mode = 0;
|
|
}
|
|
|
|
// Scalar implementation
|
|
for(u32_t i = 0; i < iterations_per_call && keep_running; i++)
|
|
{
|
|
sha1(coin, hash);
|
|
total_attempts++;
|
|
|
|
if(is_valid_coin(hash))
|
|
{
|
|
if(found_coins_count < 1024)
|
|
{
|
|
memcpy(found_coins[found_coins_count], coin, sizeof(coin));
|
|
found_coins_count++;
|
|
}
|
|
coins_found++;
|
|
|
|
#ifndef __EMSCRIPTEN__
|
|
printf("COIN FOUND! (attempt %llu)\n", (unsigned long long)total_attempts);
|
|
save_coin(coin);
|
|
#endif
|
|
}
|
|
|
|
increment_coin(coin);
|
|
}
|
|
|
|
return keep_running;
|
|
}
|
|
|
|
//
|
|
// Get mining statistics
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
void get_statistics(u64_t *attempts, u32_t *coins, double *hash_rate, double *elapsed_time)
|
|
{
|
|
*attempts = total_attempts;
|
|
*coins = coins_found;
|
|
|
|
double current_time = get_time();
|
|
double actual_elapsed;
|
|
|
|
if(!keep_running && last_pause_time > 0) {
|
|
actual_elapsed = last_pause_time - mining_start_time - pause_time_offset;
|
|
} else {
|
|
actual_elapsed = current_time - mining_start_time - pause_time_offset;
|
|
}
|
|
|
|
*elapsed_time = actual_elapsed;
|
|
*hash_rate = (actual_elapsed > 0) ? (total_attempts / actual_elapsed) : 0;
|
|
}
|
|
|
|
//
|
|
// Enable/disable SIMD
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
void set_simd_enabled(int enabled)
|
|
{
|
|
use_simd = enabled;
|
|
printf("C: SIMD mode set to: %d\n", use_simd);
|
|
}
|
|
|
|
//
|
|
// Check if SIMD is available
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
int is_simd_available()
|
|
{
|
|
#if defined(__wasm_simd128__)
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Get current SIMD state
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
int is_simd_enabled()
|
|
{
|
|
return use_simd;
|
|
}
|
|
|
|
//
|
|
// Stop mining
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
void stop_mining()
|
|
{
|
|
if(keep_running) {
|
|
keep_running = 0;
|
|
last_pause_time = get_time();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resume mining
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
void resume_mining()
|
|
{
|
|
if(!keep_running && last_pause_time > 0) {
|
|
double pause_duration = get_time() - last_pause_time;
|
|
pause_time_offset += pause_duration;
|
|
keep_running = 1;
|
|
last_pause_time = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get found coin data
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
u32_t* get_found_coin(u32_t index)
|
|
{
|
|
if(index < found_coins_count)
|
|
return found_coins[index];
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get number of found coins
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
u32_t get_found_coins_count()
|
|
{
|
|
return found_coins_count;
|
|
}
|
|
|
|
//
|
|
// Reset mining state
|
|
//
|
|
#ifdef __EMSCRIPTEN__
|
|
EMSCRIPTEN_KEEPALIVE
|
|
#endif
|
|
void reset_mining()
|
|
{
|
|
keep_running = 1;
|
|
total_attempts = 0;
|
|
coins_found = 0;
|
|
found_coins_count = 0;
|
|
pause_time_offset = 0;
|
|
last_pause_time = 0;
|
|
mining_start_time = get_time();
|
|
}
|
|
|
|
//
|
|
// Main function (for standalone compilation/testing)
|
|
//
|
|
#ifndef __EMSCRIPTEN__
|
|
int main(int argc, char *argv[])
|
|
{
|
|
u64_t max_attempts = 0;
|
|
|
|
if(argc > 1)
|
|
max_attempts = strtoull(argv[1], NULL, 10);
|
|
|
|
printf("Mining DETI coins using WebAssembly implementation (standalone mode)...\n");
|
|
#if defined(__wasm_simd128__)
|
|
printf("SIMD support: available\n");
|
|
use_simd = 1;
|
|
#else
|
|
printf("SIMD support: not available\n");
|
|
#endif
|
|
printf("Press Ctrl+C to stop\n\n");
|
|
|
|
time_measurement();
|
|
time_measurement();
|
|
double start_time = wall_time_delta();
|
|
double last_report = start_time;
|
|
|
|
while(keep_running && (max_attempts == 0 || total_attempts < max_attempts))
|
|
{
|
|
mine_coins_wasm(100000);
|
|
|
|
time_measurement();
|
|
double current_time = wall_time_delta() - start_time;
|
|
|
|
if(current_time - last_report >= 1.0)
|
|
{
|
|
u64_t attempts;
|
|
u32_t coins;
|
|
double hash_rate, elapsed;
|
|
get_statistics(&attempts, &coins, &hash_rate, &elapsed);
|
|
|
|
printf("Attempts: %llu, Rate: %.2f MH/s, Coins: %u\n",
|
|
(unsigned long long)attempts, hash_rate / 1e6, coins);
|
|
|
|
last_report = current_time;
|
|
}
|
|
}
|
|
|
|
time_measurement();
|
|
double total_time = wall_time_delta() - start_time;
|
|
|
|
printf("\n=== Mining Statistics ===\n");
|
|
printf("Total attempts: %llu\n", (unsigned long long)total_attempts);
|
|
printf("Total time: %.2f seconds\n", total_time);
|
|
printf("Average rate: %.2f attempts/second\n", total_attempts / total_time);
|
|
printf("Coins found: %u\n", coins_found);
|
|
|
|
save_coin(NULL);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|