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}