spongefish_pow/
keccak.rs

1use super::PowStrategy;
2
3#[derive(Clone, Copy)]
4pub struct KeccakPoW {
5    challenge: [u64; 4],
6    threshold: u64,
7    state: [u64; 25],
8}
9
10impl PowStrategy for KeccakPoW {
11    #[allow(clippy::cast_sign_loss)]
12    fn new(challenge: [u8; 32], bits: f64) -> Self {
13        let threshold = (64.0 - bits).exp2().ceil() as u64;
14        Self {
15            challenge: bytemuck::cast(challenge),
16            threshold,
17            state: [0; 25],
18        }
19    }
20
21    fn check(&mut self, nonce: u64) -> bool {
22        self.state[..4].copy_from_slice(&self.challenge);
23        self.state[4] = nonce;
24        for s in self.state.iter_mut().skip(5) {
25            *s = 0;
26        }
27        keccak::f1600(&mut self.state);
28        self.state[0] < self.threshold
29    }
30}
31
32#[test]
33fn test_pow_keccak() {
34    use spongefish::{DefaultHash, DomainSeparator};
35
36    use crate::{
37        ByteDomainSeparator, BytesToUnitDeserialize, BytesToUnitSerialize, PoWChallenge,
38        PoWDomainSeparator,
39    };
40
41    const BITS: f64 = 10.0;
42
43    let domain_separator = DomainSeparator::<DefaultHash>::new("the proof of work lottery 🎰")
44        .add_bytes(1, "something")
45        .challenge_pow("rolling dices");
46
47    let mut prover = domain_separator.to_prover_state();
48    prover.add_bytes(b"\0").expect("Invalid DomainSeparator");
49    prover.challenge_pow::<KeccakPoW>(BITS).unwrap();
50
51    let mut verifier = domain_separator.to_verifier_state(prover.narg_string());
52    let byte = verifier.next_bytes::<1>().unwrap();
53    assert_eq!(&byte, b"\0");
54    verifier.challenge_pow::<KeccakPoW>(BITS).unwrap();
55}