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