ab_proof_of_space/
chia.rs

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