1use super::PowStrategy;
2use crate::PoWSolution;
3use ::keccak::{Keccak, State1600};
4
5#[derive(Clone, Copy)]
6pub struct KeccakPoW {
7 challenge: [u64; 4],
8 threshold: u64,
9 state: [u64; 25],
10}
11
12impl PowStrategy for KeccakPoW {
13 #[allow(clippy::cast_sign_loss)]
14 fn new(challenge: [u8; 32], bits: f64) -> Self {
15 let threshold = (64.0 - bits).exp2().ceil() as u64;
16 Self {
17 challenge: bytemuck::cast(challenge),
18 threshold,
19 state: [0; 25],
20 }
21 }
22
23 fn solution(&self, nonce: u64) -> PoWSolution {
24 PoWSolution {
25 challenge: bytemuck::cast(self.challenge),
26 nonce,
27 }
28 }
29
30 fn check(&mut self, nonce: u64) -> bool {
31 self.state[..4].copy_from_slice(&self.challenge);
32 self.state[4] = nonce;
33 for s in self.state.iter_mut().skip(5) {
34 *s = 0;
35 }
36 f1600(&mut self.state);
37 self.state[0] < self.threshold
38 }
39}
40
41fn f1600(state: &mut State1600) {
42 Keccak::new().with_f1600(|f1600| f1600(state));
43}
44
45#[test]
46fn test_pow_keccak() {
47 use crate::{convenience::*, PoWGrinder};
48
49 const BITS: f64 = 10.0;
50
51 let challenge = [42u8; 32];
53
54 let _solution = grind_pow::<KeccakPoW>(challenge, BITS).expect("Should find a valid solution");
56
57 let mut grounder = PoWGrinder::<KeccakPoW>::new(challenge, BITS);
60 let _solution2 = grounder.grind().expect("Should find a valid solution");
61
62 assert!(grind_pow::<KeccakPoW>(challenge, BITS).is_some());
65}