Skip to content

Commit

Permalink
Add keccak
Browse files Browse the repository at this point in the history
  • Loading branch information
WizardOfMenlo committed Sep 6, 2024
1 parent fb54c5b commit 5537a3b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 2 deletions.
31 changes: 31 additions & 0 deletions src/plugins/pow/keccak.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use super::PowStrategy;

#[derive(Clone, Copy)]
pub struct KeccakPoW {
challenge: [u64; 4],
threshold: u64,
state: [u64; 25],
}

impl PowStrategy for KeccakPoW {
fn new(challenge: [u8; 32], bits: f64) -> Self {
let threshold = (64.0 - bits).exp2().ceil() as u64;
Self {
challenge: bytemuck::cast(challenge),
threshold,
state: [0; 25],
}
}

/// This deliberately uses the high level interface to guarantee
/// compatibility with standard Blake3.
fn check(&mut self, nonce: u64) -> bool {
self.state[..4].copy_from_slice(&self.challenge);
self.state[4] = nonce;
for s in self.state.iter_mut().skip(5) {
*s = 0;
}
keccak::f1600(&mut self.state);
self.state[0] < self.threshold
}
}
41 changes: 39 additions & 2 deletions src/plugins/pow/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod blake3;
mod keccak;

use crate::{
Arthur, ByteChallenges, ByteIOPattern, ByteReader, ByteWriter, IOPattern, Merlin, ProofError,
Expand Down Expand Up @@ -60,7 +61,7 @@ where
}
}

pub trait PowStrategy {
pub trait PowStrategy: Clone + Sync {
/// Creates a new proof-of-work challenge.
/// The `challenge` is a 32-byte array that represents the challenge.
/// The `bits` is the binary logarithm of the expected amount of work.
Expand All @@ -71,5 +72,41 @@ pub trait PowStrategy {
fn check(&mut self, nonce: u64) -> bool;

/// Finds the minimal `nonce` that satisfies the challenge.
fn solve(&mut self) -> Option<u64>;
#[cfg(not(feature = "parallel"))]
fn solve(&mut self) -> Option<u64> {
// TODO: Parallel default impl
(0u64..).find_map(|nonce| if self.check(nonce) { Some(nonce) } else { None })
}

#[cfg(feature = "parallel")]
fn solve(&mut self) -> Option<u64> {
// Split the work across all available threads.
// Use atomics to find the unique deterministic lowest satisfying nonce.

use std::sync::atomic::{AtomicU64, Ordering};

use rayon::broadcast;
let global_min = AtomicU64::new(u64::MAX);
let _ = broadcast(|ctx| {
let mut worker = self.clone();
let nonces = (ctx.index() as u64..).step_by(ctx.num_threads());
for nonce in nonces {
// Use relaxed ordering to eventually get notified of another thread's solution.
// (Propagation delay should be in the order of tens of nanoseconds.)
if nonce >= global_min.load(Ordering::Relaxed) {
break;
}
if worker.check(nonce) {
// We found a solution, store it in the global_min.
// Use fetch_min to solve race condition with simultaneous solutions.
global_min.fetch_min(nonce, Ordering::SeqCst);
break;
}
}
});
match global_min.load(Ordering::SeqCst) {
u64::MAX => self.check(u64::MAX).then_some(u64::MAX),
nonce => Some(nonce),
}
}
}

0 comments on commit 5537a3b

Please sign in to comment.