subspace_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
4use crate::{PosTableType, Table, TableGenerator};
5use core::iter;
6use subspace_core_primitives::hashes::blake3_hash;
7use subspace_core_primitives::pos::{PosProof, PosSeed};
8use subspace_core_primitives::U256;
9
10/// Subspace proof of space table generator.
11///
12/// Shim implementation.
13#[derive(Debug, Default, Clone)]
14pub struct ShimTableGenerator;
15
16impl TableGenerator<ShimTable> for ShimTableGenerator {
17    fn generate(&mut self, seed: &PosSeed) -> ShimTable {
18        ShimTable::generate(seed)
19    }
20}
21
22/// Subspace proof of space table.
23///
24/// Shim implementation.
25#[derive(Debug)]
26pub struct ShimTable {
27    seed: PosSeed,
28}
29
30impl Table for ShimTable {
31    const TABLE_TYPE: PosTableType = PosTableType::Shim;
32    type Generator = ShimTableGenerator;
33    fn generate(seed: &PosSeed) -> ShimTable {
34        Self { seed: *seed }
35    }
36
37    fn find_proof(&self, challenge_index: u32) -> Option<PosProof> {
38        find_proof(&self.seed, challenge_index)
39    }
40
41    fn is_proof_valid(seed: &PosSeed, challenge_index: u32, proof: &PosProof) -> bool {
42        let Some(correct_proof) = find_proof(seed, challenge_index) else {
43            return false;
44        };
45
46        &correct_proof == proof
47    }
48}
49
50fn find_proof(seed: &PosSeed, challenge_index: u32) -> Option<PosProof> {
51    let quality = blake3_hash(&challenge_index.to_le_bytes());
52    if U256::from_le_bytes(*quality) % U256::from(3u32) > U256::zero() {
53        let mut proof = PosProof::default();
54        proof
55            .iter_mut()
56            .zip(seed.iter().chain(iter::repeat(quality.iter()).flatten()))
57            .for_each(|(output, input)| {
58                *output = *input;
59            });
60
61        Some(proof)
62    } else {
63        None
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn basic() {
73        let seed = PosSeed::from([
74            35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
75            198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
76        ]);
77
78        let table = ShimTable::generate(&seed);
79
80        assert!(table.find_proof(0).is_none());
81
82        {
83            let challenge_index = 2;
84            let proof = table.find_proof(challenge_index).unwrap();
85            assert!(ShimTable::is_proof_valid(&seed, challenge_index, &proof));
86        }
87    }
88}