use crate::Particle;
fn score(event_hash: &Particle, nonce: u64) -> u64 {
let mut input = [0u8; 40];
input[..32].copy_from_slice(event_hash);
input[32..].copy_from_slice(&nonce.to_le_bytes());
let h = hemera::hash(&input);
let b = h.as_bytes();
u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
}
pub fn verify(event_hash: &Particle, nonce: u64, target: u64) -> bool {
score(event_hash, nonce) < target
}
pub fn solve(event_hash: &Particle, target: u64) -> u64 {
let mut nonce = 0u64;
loop {
if verify(event_hash, nonce, target) {
return nonce;
}
nonce = nonce.wrapping_add(1);
}
}
pub fn target_from_difficulty(expected_hashes: u64) -> u64 {
if expected_hashes <= 1 {
return u64::MAX;
}
u64::MAX / expected_hashes
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn solve_then_verify() {
let event_hash = [7u8; 32];
let target = target_from_difficulty(16);
let nonce = solve(&event_hash, target);
assert!(verify(&event_hash, nonce, target));
}
#[test]
fn wrong_nonce_fails_hard_target() {
let event_hash = [9u8; 32];
assert!(!verify(&event_hash, 12345, 1));
}
#[test]
fn difficulty_maps_sanely() {
assert_eq!(target_from_difficulty(0), u64::MAX);
assert_eq!(target_from_difficulty(1), u64::MAX);
assert!(target_from_difficulty(100) < target_from_difficulty(10));
}
}