spongefish_pow/
keccak.rs

1use super::PowStrategy;
2use crate::PoWSolution;
3
4#[derive(Clone, Copy)]
5pub struct KeccakPoW {
6    challenge: [u64; 4],
7    threshold: u64,
8    state: [u64; 25],
9}
10
11impl PowStrategy for KeccakPoW {
12    #[allow(clippy::cast_sign_loss)]
13    fn new(challenge: [u8; 32], bits: f64) -> Self {
14        let threshold = (64.0 - bits).exp2().ceil() as u64;
15        Self {
16            challenge: bytemuck::cast(challenge),
17            threshold,
18            state: [0; 25],
19        }
20    }
21
22    fn solution(&self, nonce: u64) -> PoWSolution {
23        PoWSolution {
24            challenge: bytemuck::cast(self.challenge),
25            nonce,
26        }
27    }
28
29    fn check(&mut self, nonce: u64) -> bool {
30        self.state[..4].copy_from_slice(&self.challenge);
31        self.state[4] = nonce;
32        for s in self.state.iter_mut().skip(5) {
33            *s = 0;
34        }
35        keccak::f1600(&mut self.state);
36        self.state[0] < self.threshold
37    }
38}
39
40#[test]
41fn test_pow_keccak() {
42    use crate::{convenience::*, PoWGrinder};
43
44    const BITS: f64 = 10.0;
45
46    // Test with a fixed challenge
47    let challenge = [42u8; 32];
48
49    // Generate a proof-of-work solution
50    let _solution = grind_pow::<KeccakPoW>(challenge, BITS).expect("Should find a valid solution");
51
52    // We can't extract the nonce directly from the solution (it's one-way),
53    // but we can verify by re-grinding and checking we get a valid solution
54    let mut grounder = PoWGrinder::<KeccakPoW>::new(challenge, BITS);
55    let _solution2 = grounder.grind().expect("Should find a valid solution");
56
57    // Both solutions should be valid (though they contain different nonces)
58    // We verify by checking that grinding succeeds
59    assert!(grind_pow::<KeccakPoW>(challenge, BITS).is_some());
60}