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 = *blake3::hash(&challenge_index.to_le_bytes()).as_bytes();
69    if quality[0] % 3 > 0 {
70        let mut proof = PosProof::default();
71        proof
72            .iter_mut()
73            .zip(seed.iter().chain(iter::repeat(quality.iter()).flatten()))
74            .for_each(|(output, input)| {
75                *output = *input;
76            });
77
78        Some(proof)
79    } else {
80        None
81    }
82}
83
84#[cfg(all(feature = "alloc", test))]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn basic() {
90        let seed = PosSeed::from([
91            35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
92            198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
93        ]);
94
95        let table = ShimTable::generate(&seed);
96
97        assert!(table.find_proof(1).is_none());
98
99        {
100            let challenge_index = 0;
101            let proof = table.find_proof(challenge_index).unwrap();
102            assert!(ShimTable::is_proof_valid(&seed, challenge_index, &proof));
103        }
104    }
105}