subspace_proof_of_space/
chia.rs

1//! Chia proof of space implementation
2use crate::chiapos::{Tables, TablesCache};
3use crate::{PosTableType, Table, TableGenerator};
4use core::mem;
5use subspace_core_primitives::pos::{PosProof, PosSeed};
6
7const K: u8 = PosProof::K;
8
9/// Subspace proof of space table generator.
10///
11/// Chia implementation.
12#[derive(Debug, Default, Clone)]
13pub struct ChiaTableGenerator {
14    tables_cache: TablesCache<K>,
15}
16
17impl TableGenerator<ChiaTable> for ChiaTableGenerator {
18    fn generate(&mut self, seed: &PosSeed) -> ChiaTable {
19        ChiaTable {
20            tables: Tables::<K>::create((*seed).into(), &mut self.tables_cache),
21        }
22    }
23
24    #[cfg(any(feature = "parallel", test))]
25    fn generate_parallel(&mut self, seed: &PosSeed) -> ChiaTable {
26        ChiaTable {
27            tables: Tables::<K>::create_parallel((*seed).into(), &mut self.tables_cache),
28        }
29    }
30}
31
32/// Subspace proof of space table.
33///
34/// Chia implementation.
35#[derive(Debug)]
36pub struct ChiaTable {
37    tables: Tables<K>,
38}
39
40impl Table for ChiaTable {
41    const TABLE_TYPE: PosTableType = PosTableType::Chia;
42    type Generator = ChiaTableGenerator;
43
44    fn generate(seed: &PosSeed) -> ChiaTable {
45        Self {
46            tables: Tables::<K>::create_simple((*seed).into()),
47        }
48    }
49
50    #[cfg(any(feature = "parallel", test))]
51    fn generate_parallel(seed: &PosSeed) -> ChiaTable {
52        Self {
53            tables: Tables::<K>::create_parallel((*seed).into(), &mut TablesCache::default()),
54        }
55    }
56
57    fn find_proof(&self, challenge_index: u32) -> Option<PosProof> {
58        let mut challenge = [0; 32];
59        challenge[..mem::size_of::<u32>()].copy_from_slice(&challenge_index.to_le_bytes());
60
61        let proof = self
62            .tables
63            .find_proof(&challenge)
64            .next()
65            .map(PosProof::from);
66        proof
67    }
68
69    fn is_proof_valid(seed: &PosSeed, challenge_index: u32, proof: &PosProof) -> bool {
70        let mut challenge = [0; 32];
71        challenge[..mem::size_of::<u32>()].copy_from_slice(&challenge_index.to_le_bytes());
72        Tables::<K>::verify(**seed, &challenge, proof).is_some()
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn basic() {
82        let seed = PosSeed::from([
83            35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
84            198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
85        ]);
86
87        let table = ChiaTable::generate(&seed);
88        let table_parallel = ChiaTable::generate_parallel(&seed);
89
90        assert!(table.find_proof(1232460437).is_none());
91        assert!(table_parallel.find_proof(1232460437).is_none());
92
93        {
94            let challenge_index = 600426542;
95            let proof = table.find_proof(challenge_index).unwrap();
96            assert_eq!(proof, table_parallel.find_proof(challenge_index).unwrap());
97            assert!(ChiaTable::is_proof_valid(&seed, challenge_index, &proof));
98        }
99    }
100}