PoW generation stuff along with brute force
This commit is contained in:
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user