PoW generation stuff along with brute force

This commit is contained in:
Mars Ultor
2025-04-20 00:08:13 -05:00
parent df5ae14758
commit bd33d38f58
6 changed files with 131 additions and 1 deletions
+1
View File
@@ -16,3 +16,4 @@ socket2 = "0.5.9"
serde = { version = "1.0", features = ["derive"] }
serde-big-array = "0.5"
postcard = "1.0.0"
threadpool = "1.8.1"
+98 -1
View File
@@ -1,5 +1,5 @@
// always use the following derive flags: #[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
/*
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;
const CHALLENGE_DIFF: usize = 40;
@@ -18,3 +18,100 @@ pub struct PowChallengeResponse{
secret: [u8; CHALLENGE_DIFF/BITS_IN_BYTE],
}
*/
use sha2::{Sha512, Digest};
use rand::RngCore;
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;
use threadpool::ThreadPool;
use std::sync::{Arc, Mutex};
const CHALLENGE_DIFF: usize = 40;
const SHA_LENGTH: usize = 512;
const BITS_IN_BYTE: usize = 8;
#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
pub struct PowChallengeQuery {
#[serde(with = "BigArray")]
hash: [u8; SHA_LENGTH / BITS_IN_BYTE],
}
#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
pub struct PowChallengeResponse {
#[serde(with = "BigArray")]
hash: [u8; SHA_LENGTH / BITS_IN_BYTE],
#[serde(with = "BigArray")]
secret: [u8; CHALLENGE_DIFF / BITS_IN_BYTE],
}
impl PowChallengeResponse {
/// Randomly generates a secret and computes its SHA-512 hash.
pub fn generate() -> Self {
let mut secret = [0u8; CHALLENGE_DIFF / BITS_IN_BYTE];
rand::thread_rng().fill_bytes(&mut secret);
let mut hasher = Sha512::new();
hasher.update(&secret);
let hash = hasher.finalize();
let mut hash_bytes = [0u8; SHA_LENGTH / BITS_IN_BYTE];
hash_bytes.copy_from_slice(&hash);
Self {
hash: hash_bytes,
secret,
}
}
/// Attempts to brute-force the secret given a hash in the query.
/// This method enumerates the possible secrets using a thread pool.
pub fn brute_force(query: &PowChallengeQuery, num_threads: usize) -> Option<Self> {
let pool = ThreadPool::new(num_threads);
let result = Arc::new(Mutex::new(None));
// Iterate over the possible candidate combinations.
for i in 0.. {
// For each job, check a single candidate secret
let result = Arc::clone(&result);
let query = query.clone();
pool.execute(move || {
let mut candidate = [0u8; CHALLENGE_DIFF / BITS_IN_BYTE];
let mut temp = i;
// Fill the candidate with the correct byte values based on `i`
for byte in &mut candidate {
*byte = (temp & 0xFF) as u8;
temp >>= 8;
}
let mut hasher = Sha512::new();
hasher.update(&candidate);
let hash = hasher.finalize();
let mut hash_bytes = [0u8; SHA_LENGTH / BITS_IN_BYTE];
hash_bytes.copy_from_slice(&hash);
// If a match is found, lock the result and return it
if hash_bytes == query.hash {
let mut locked_result = result.lock().unwrap();
if locked_result.is_none() {
*locked_result = Some(Self {
hash: hash_bytes,
secret: candidate,
});
}
}
});
// For large challenge sizes, exit early after trying a reasonable number of iterations
// to prevent the loop from becoming too long if we have not found the secret.
// This step is optional and depends on your use case.
}
pool.join();
let locked_result = result.lock().unwrap();
locked_result.clone()
}
}