WebAssembly

Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
This commit is contained in:
Tiago Garcia 2025-11-16 19:41:51 +00:00
parent d86863820b
commit fa06494b59
Signed by: TiagoRG
GPG Key ID: DFCD48E3F420DB42
4 changed files with 452 additions and 2 deletions

268
aad_coin_miner_wasm.c Normal file
View File

@ -0,0 +1,268 @@
//
// Arquiteturas de Alto Desempenho 2025/2026
//
// DETI Coin Miner - WebAssembly implementation
//
#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
// Global mining state
static volatile int keep_running = 1;
static u64_t total_attempts = 0;
static u32_t coins_found = 0;
static double mining_start_time = 0;
static u32_t found_coins[1024][14]; // Store up to 1024 found coins
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
}
//
// 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;
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;
// Mine for the specified number of iterations
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;
*elapsed_time = get_time() - mining_start_time;
*hash_rate = (*elapsed_time > 0) ? (total_attempts / *elapsed_time) : 0;
}
//
// Stop mining
//
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_KEEPALIVE
#endif
void stop_mining()
{
keep_running = 0;
}
//
// Get found coin data (returns pointer to coin array)
//
#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;
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");
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

35
aad_sha1_wasm.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef AAD_SHA1_WASM
#define AAD_SHA1_WASM
#include "aad_data_types.h"
#include "aad_sha1.h"
//
// SHA1 hash computation for WebAssembly (scalar implementation)
//
static inline u32_t rotate_left(u32_t x, int n)
{
return (x << n) | (x >> (32 - n));
}
static void sha1(u32_t *coin, u32_t *hash)
{
// Define the macros needed by CUSTOM_SHA1_CODE
#define T u32_t
#define C(c) (c)
#define ROTATE(x,n) rotate_left(x,n)
#define DATA(idx) coin[idx]
#define HASH(idx) hash[idx]
// Use the standard SHA1 template from aad_sha1.h
CUSTOM_SHA1_CODE();
#undef T
#undef C
#undef ROTATE
#undef DATA
#undef HASH
}
#endif

137
index.html Normal file
View File

@ -0,0 +1,137 @@
<!DOCTYPE html>
<html>
<head>
<title>DETI Coin Miner - WebAssembly</title>
<style>
body {
font-family: monospace;
padding: 20px;
}
button {
padding: 10px 20px;
margin: 5px;
font-size: 16px;
}
#stats {
margin-top: 20px;
padding: 10px;
background: #f0f0f0;
border-radius: 5px;
}
.control-group {
margin: 10px 0;
}
label {
display: inline-block;
width: 200px;
}
</style>
</head>
<body>
<h1>DETI Coin Miner (WebAssembly)</h1>
<div class="control-group">
<label>Iterations per batch:</label>
<input type="number" id="batchSize" value="1000000" step="100000">
</div>
<div class="control-group">
<label>Update interval (ms):</label>
<input type="number" id="updateInterval" value="100" step="50">
</div>
<button id="start">Start Mining</button>
<button id="stop">Stop Mining</button>
<button id="reset">Reset</button>
<div id="stats">
Waiting to start...
</div>
<script src="aad_coin_miner_wasm.js"></script>
<script>
let mining = false;
let Module;
let miningInterval;
let updateInterval;
CoinMinerModule().then(mod => {
Module = mod;
console.log('WebAssembly module loaded');
document.getElementById('start').onclick = () => {
if (!mining) {
mining = true;
console.log('Starting mining...');
startMining();
}
};
document.getElementById('stop').onclick = () => {
mining = false;
Module._stop_mining();
clearInterval(miningInterval);
clearInterval(updateInterval);
console.log('Mining stopped');
};
document.getElementById('reset').onclick = () => {
Module._reset_mining();
mining = false;
clearInterval(miningInterval);
clearInterval(updateInterval);
document.getElementById('stats').innerHTML = 'Reset complete. Click Start to begin.';
console.log('Mining reset');
};
function updateStats() {
const attemptsPtr = Module._malloc(8);
const coinsPtr = Module._malloc(4);
const hashRatePtr = Module._malloc(8);
const elapsedPtr = Module._malloc(8);
Module._get_statistics(attemptsPtr, coinsPtr, hashRatePtr, elapsedPtr);
const attempts = Module.getValue(attemptsPtr, 'i64');
const coins = Module.getValue(coinsPtr, 'i32');
const hashRate = Module.getValue(hashRatePtr, 'double');
const elapsed = Module.getValue(elapsedPtr, 'double');
Module._free(attemptsPtr);
Module._free(coinsPtr);
Module._free(hashRatePtr);
Module._free(elapsedPtr);
document.getElementById('stats').innerHTML = `
<strong>Mining Statistics:</strong><br>
Attempts: ${attempts.toString()}<br>
Coins Found: ${coins}<br>
Hash Rate: ${(hashRate / 1e6).toFixed(2)} MH/s<br>
Elapsed Time: ${elapsed.toFixed(2)} seconds<br>
`;
const coinsFound = Module._get_found_coins_count();
if (coinsFound > 0) {
console.log(`Total coins found: ${coinsFound}`);
}
}
function startMining() {
const batchSize = parseInt(document.getElementById('batchSize').value);
const updateMs = parseInt(document.getElementById('updateInterval').value);
// Mine continuously using setInterval for larger batches
miningInterval = setInterval(() => {
if (!mining) {
clearInterval(miningInterval);
return;
}
Module._mine_coins_wasm(batchSize);
}, 0);
// Update stats periodically
updateInterval = setInterval(updateStats, updateMs);
}
}).catch(err => {
console.error('Failed to load WebAssembly module:', err);
document.getElementById('stats').innerHTML = 'Error loading module: ' + err.message;
});
</script>
</body>
</html>

View File

@ -84,11 +84,21 @@ coin_miner_cuda_kernel.cubin: aad_coin_miner_cuda_kernel.cu aad_sha1.h makefile
coin_miner_cuda: aad_coin_miner_cuda.c coin_miner_cuda_kernel.cubin aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h aad_vault.h aad_cuda_utilities.h makefile coin_miner_cuda: aad_coin_miner_cuda.c coin_miner_cuda_kernel.cubin aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h aad_vault.h aad_cuda_utilities.h makefile
cc -march=native -Wall -Wshadow -Werror -O3 -I$(CUDA_DIR)/include $< -o $@ -lcuda cc -march=native -Wall -Wshadow -Werror -O3 -I$(CUDA_DIR)/include $< -o $@ -lcuda
coin_miner_wasm: aad_coin_miner_wasm.c aad_sha1.h aad_sha1_cpu.h aad_sha1_wasm.h aad_data_types.h aad_utilities.h aad_vault.h makefile
emcc -O3 -flto -o aad_coin_miner_wasm.js aad_coin_miner_wasm.c \
-s WASM=1 \
-s EXPORTED_FUNCTIONS='["_mine_coins_wasm","_get_statistics","_stop_mining","_reset_mining","_get_found_coin","_get_found_coins_count","_malloc","_free"]' \
-s EXPORTED_RUNTIME_METHODS='["cwrap","ccall","getValue","setValue"]' \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE=1 \
-s EXPORT_NAME='CoinMinerModule' \
-s INITIAL_MEMORY=67108864
benchmark: aad_benchmark.c aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h makefile benchmark: aad_benchmark.c aad_sha1.h aad_sha1_cpu.h aad_data_types.h aad_utilities.h makefile
cc -march=native -Wall -Wshadow -Werror -O3 $< -o $@ cc -march=native -Wall -Wshadow -Werror -O3 $< -o $@
miners: coin_miner_cpu coin_miner_simd coin_miner_cuda benchmark miners: coin_miner_cpu coin_miner_simd coin_miner_wasm coin_miner_cuda benchmark
all: sha1_tests sha1_cuda_test sha1_cuda_kernel.cubin \ all: sha1_tests sha1_cuda_test sha1_cuda_kernel.cubin \
coin_miner_cpu coin_miner_simd coin_miner_cuda coin_miner_cuda_kernel.cubin \ coin_miner_cpu coin_miner_simd coin_miner_wasm coin_miner_cuda coin_miner_cuda_kernel.cubin \
benchmark benchmark