separate wgsl file
This commit is contained in:
@@ -20,110 +20,8 @@ async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.request_device(&wgpu::DeviceDescriptor::default())
|
||||
.await?;
|
||||
|
||||
// Create simplified WGSL mining shader (basic hash function for testing)
|
||||
let shader_source = r#"
|
||||
// Storage buffers
|
||||
@group(0) @binding(0) var<storage, read_write> results: array<u32>;
|
||||
@group(0) @binding(1) var<storage, read> header: array<u32, 8>; // 32 bytes
|
||||
@group(0) @binding(2) var<storage, read> start_nonce: array<u32, 16>; // 64 bytes
|
||||
@group(0) @binding(3) var<storage, read> difficulty_target: array<u32, 16>; // 64 bytes (U512 target)
|
||||
|
||||
// Simple hash function (placeholder for now)
|
||||
fn simple_hash(input: array<u32, 24>) -> array<u32, 16> {
|
||||
var result: array<u32, 16>;
|
||||
|
||||
// Very simple hash: XOR all input values and spread to output
|
||||
var hash_val = 0u;
|
||||
for (var i = 0u; i < 24u; i++) {
|
||||
hash_val = hash_val ^ input[i];
|
||||
hash_val = hash_val * 1103515245u + 12345u; // Simple LCG
|
||||
}
|
||||
|
||||
// Fill output array with variations of hash
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
hash_val = hash_val * 1103515245u + 12345u;
|
||||
result[i] = hash_val;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Double hash
|
||||
fn double_hash(input: array<u32, 24>) -> array<u32, 16> {
|
||||
let first_hash = simple_hash(input);
|
||||
// Convert back to input format for second hash
|
||||
var second_input: array<u32, 24>;
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
second_input[i] = first_hash[i];
|
||||
}
|
||||
// Pad remaining with zeros
|
||||
for (var i = 16u; i < 24u; i++) {
|
||||
second_input[i] = 0u;
|
||||
}
|
||||
return simple_hash(second_input);
|
||||
}
|
||||
|
||||
// Check if hash < target (U512 comparison)
|
||||
fn is_below_target(hash: array<u32, 16>, difficulty_tgt: array<u32, 16>) -> bool {
|
||||
// Compare from most significant to least significant
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
if (hash[15u - i] < difficulty_tgt[15u - i]) {
|
||||
return true;
|
||||
} else if (hash[15u - i] > difficulty_tgt[15u - i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false; // Equal, not below
|
||||
}
|
||||
|
||||
@compute @workgroup_size(64)
|
||||
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
||||
let thread_id = id.x;
|
||||
|
||||
// Prepare mining input: header (32 bytes) + nonce (64 bytes)
|
||||
var mining_input: array<u32, 24>; // 96 bytes total
|
||||
|
||||
// Copy header (32 bytes = 8 u32s)
|
||||
for (var i = 0u; i < 8u; i++) {
|
||||
mining_input[i] = header[i];
|
||||
}
|
||||
|
||||
// Calculate nonce for this thread
|
||||
var nonce: array<u32, 16> = start_nonce;
|
||||
// Add thread_id to the nonce (simplified increment)
|
||||
var carry = thread_id;
|
||||
for (var i = 0u; i < 16u && carry > 0u; i++) {
|
||||
let old_val = nonce[i];
|
||||
nonce[i] = old_val + carry;
|
||||
// Check for overflow
|
||||
if (nonce[i] < old_val) {
|
||||
carry = 1u;
|
||||
} else {
|
||||
carry = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy nonce (64 bytes = 16 u32s)
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
mining_input[8u + i] = nonce[i];
|
||||
}
|
||||
|
||||
// Compute double Poseidon2 hash
|
||||
let hash_result = double_hash(mining_input);
|
||||
|
||||
// Check if hash meets difficulty target
|
||||
if (is_below_target(hash_result, difficulty_target)) {
|
||||
// Found a valid nonce! Store it in results
|
||||
results[0] = 1u; // Success flag
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
results[i + 1u] = nonce[i]; // Store winning nonce
|
||||
}
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
results[i + 17u] = hash_result[i]; // Store winning hash
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
// Load WGSL shader from external file
|
||||
let shader_source = include_str!("mining.wgsl");
|
||||
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("Compute Shader"),
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Quantus Mining Shader - WGSL Compute Shader for GPU Mining
|
||||
// Uses simplified hash function (to be replaced with Poseidon2)
|
||||
|
||||
// Storage buffers
|
||||
@group(0) @binding(0) var<storage, read_write> results: array<u32>;
|
||||
@group(0) @binding(1) var<storage, read> header: array<u32, 8>; // 32 bytes
|
||||
@group(0) @binding(2) var<storage, read> start_nonce: array<u32, 16>; // 64 bytes
|
||||
@group(0) @binding(3) var<storage, read> difficulty_target: array<u32, 16>; // 64 bytes (U512 target)
|
||||
|
||||
// Simple hash function (placeholder for Poseidon2)
|
||||
fn simple_hash(input: array<u32, 24>) -> array<u32, 16> {
|
||||
var result: array<u32, 16>;
|
||||
|
||||
// Very simple hash: XOR all input values and spread to output
|
||||
var hash_val = 0u;
|
||||
for (var i = 0u; i < 24u; i++) {
|
||||
hash_val = hash_val ^ input[i];
|
||||
hash_val = hash_val * 1103515245u + 12345u; // Simple LCG
|
||||
}
|
||||
|
||||
// Fill output array with variations of hash
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
hash_val = hash_val * 1103515245u + 12345u;
|
||||
result[i] = hash_val;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Double hash (like Bitcoin's double SHA256)
|
||||
fn double_hash(input: array<u32, 24>) -> array<u32, 16> {
|
||||
let first_hash = simple_hash(input);
|
||||
// Convert back to input format for second hash
|
||||
var second_input: array<u32, 24>;
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
second_input[i] = first_hash[i];
|
||||
}
|
||||
// Pad remaining with zeros
|
||||
for (var i = 16u; i < 24u; i++) {
|
||||
second_input[i] = 0u;
|
||||
}
|
||||
return simple_hash(second_input);
|
||||
}
|
||||
|
||||
// Check if hash < target (U512 comparison)
|
||||
fn is_below_target(hash: array<u32, 16>, difficulty_tgt: array<u32, 16>) -> bool {
|
||||
// Compare from most significant to least significant
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
if (hash[15u - i] < difficulty_tgt[15u - i]) {
|
||||
return true;
|
||||
} else if (hash[15u - i] > difficulty_tgt[15u - i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false; // Equal, not below
|
||||
}
|
||||
|
||||
@compute @workgroup_size(64)
|
||||
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
||||
let thread_id = id.x;
|
||||
|
||||
// Prepare mining input: header (32 bytes) + nonce (64 bytes)
|
||||
var mining_input: array<u32, 24>; // 96 bytes total
|
||||
|
||||
// Copy header (32 bytes = 8 u32s)
|
||||
for (var i = 0u; i < 8u; i++) {
|
||||
mining_input[i] = header[i];
|
||||
}
|
||||
|
||||
// Calculate nonce for this thread
|
||||
var nonce: array<u32, 16> = start_nonce;
|
||||
// Add thread_id to the nonce (simplified increment)
|
||||
var carry = thread_id;
|
||||
for (var i = 0u; i < 16u && carry > 0u; i++) {
|
||||
let old_val = nonce[i];
|
||||
nonce[i] = old_val + carry;
|
||||
// Check for overflow
|
||||
if (nonce[i] < old_val) {
|
||||
carry = 1u;
|
||||
} else {
|
||||
carry = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy nonce (64 bytes = 16 u32s)
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
mining_input[8u + i] = nonce[i];
|
||||
}
|
||||
|
||||
// Compute double hash
|
||||
let hash_result = double_hash(mining_input);
|
||||
|
||||
// Check if hash meets difficulty target
|
||||
if (is_below_target(hash_result, difficulty_target)) {
|
||||
// Found a valid nonce! Store it in results
|
||||
results[0] = 1u; // Success flag
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
results[i + 1u] = nonce[i]; // Store winning nonce
|
||||
}
|
||||
for (var i = 0u; i < 16u; i++) {
|
||||
results[i + 17u] = hash_result[i]; // Store winning hash
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user