ab_proof_of_space/
shim.rs

1//! Shim proof of space implementation that works much faster than Chia and can be used for testing
2//! purposes to reduce memory and CPU usage
3
4#[cfg(feature = "alloc")]
5use crate::TableGenerator;
6use crate::{PosTableType, Table};
7use ab_core_primitives::pos::{PosProof, PosSeed};
8use core::iter;
9
10/// Proof of space table generator.
11///
12/// Shim implementation.
13#[derive(Debug, Default, Clone)]
14#[cfg(feature = "alloc")]
15pub struct ShimTableGenerator;
16
17#[cfg(feature = "alloc")]
18impl TableGenerator<ShimTable> for ShimTableGenerator {
19    fn generate(&mut self, seed: &PosSeed) -> ShimTable {
20        ShimTable::generate(seed)
21    }
22}
23
24/// Proof of space table.
25///
26/// Shim implementation.
27#[derive(Debug)]
28pub struct ShimTable {
29    #[cfg(feature = "alloc")]
30    seed: PosSeed,
31}
32
33impl ab_core_primitives::solutions::SolutionPotVerifier for ShimTable {
34    fn is_proof_valid(seed: &PosSeed, challenge_index: u32, proof: &PosProof) -> bool {
35        let Some(correct_proof) = find_proof(seed, challenge_index) else {
36            return false;
37        };
38
39        &correct_proof == proof
40    }
41}
42
43impl Table for ShimTable {
44    const TABLE_TYPE: PosTableType = PosTableType::Shim;
45    #[cfg(feature = "alloc")]
46    type Generator = ShimTableGenerator;
47
48    #[cfg(feature = "alloc")]
49    fn generate(seed: &PosSeed) -> ShimTable {
50        Self { seed: *seed }
51    }
52
53    #[cfg(feature = "alloc")]
54    fn find_proof(&self, challenge_index: u32) -> Option<PosProof> {
55        find_proof(&self.seed, challenge_index)
56    }
57
58    fn is_proof_valid(seed: &PosSeed, challenge_index: u32, proof: &PosProof) -> bool {
59        <Self as ab_core_primitives::solutions::SolutionPotVerifier>::is_proof_valid(
60            seed,
61            challenge_index,
62            proof,
63        )
64    }
65}
66
67fn find_proof(seed: &PosSeed, challenge_index: u32) -> Option<PosProof> {
68    let quality = ab_blake3::single_block_hash(&challenge_index.to_le_bytes())
69        .expect("Less than a single block worth of bytes; qed");
70    if quality[0] % 3 > 0 {
71        let mut proof = PosProof::default();
72        proof
73            .iter_mut()
74            .zip(seed.iter().chain(iter::repeat(quality.iter()).flatten()))
75            .for_each(|(output, input)| {
76                *output = *input;
77            });
78
79        Some(proof)
80    } else {
81        None
82    }
83}
84
85#[cfg(all(feature = "alloc", test))]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn basic() {
91        let seed = PosSeed::from([
92            35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
93            198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
94        ]);
95
96        let table = ShimTable::generate(&seed);
97
98        assert!(table.find_proof(1).is_none());
99
100        {
101            let challenge_index = 0;
102            let proof = table.find_proof(challenge_index).unwrap();
103            assert!(ShimTable::is_proof_valid(&seed, challenge_index, &proof));
104        }
105    }
106}