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::PosProofs;
6#[cfg(feature = "alloc")]
7use crate::TableGenerator;
8use crate::{PosTableType, Table};
9#[cfg(feature = "alloc")]
10use ab_core_primitives::pieces::Record;
11use ab_core_primitives::pos::{PosProof, PosSeed};
12use ab_core_primitives::sectors::SBucket;
13#[cfg(feature = "alloc")]
14use alloc::boxed::Box;
15use core::iter;
16
17/// Proof of space table generator.
18///
19/// Shim implementation.
20#[derive(Debug, Default, Clone)]
21#[cfg(feature = "alloc")]
22pub struct ShimTableGenerator;
23
24#[cfg(feature = "alloc")]
25impl TableGenerator<ShimTable> for ShimTableGenerator {
26    fn create_proofs(&self, seed: &PosSeed) -> Box<PosProofs> {
27        // SAFETY: Zeroed contents is a safe invariant
28        let mut proofs = unsafe { Box::<PosProofs>::new_zeroed().assume_init() };
29
30        let mut num_found_proofs = 0_usize;
31        'outer: for (s_buckets, found_proofs) in (0..Record::NUM_S_BUCKETS as u32)
32            .array_chunks::<{ u8::BITS as usize }>()
33            .zip(&mut proofs.found_proofs)
34        {
35            for (proof_offset, s_bucket) in s_buckets.into_iter().enumerate() {
36                if let Some(proof) = find_proof(seed, s_bucket) {
37                    *found_proofs |= 1 << proof_offset;
38
39                    proofs.proofs[num_found_proofs] = proof;
40                    num_found_proofs += 1;
41
42                    if num_found_proofs == Record::NUM_CHUNKS {
43                        break 'outer;
44                    }
45                }
46            }
47        }
48
49        proofs
50    }
51}
52
53/// Proof of space table.
54///
55/// Shim implementation.
56#[derive(Debug)]
57pub struct ShimTable;
58
59impl ab_core_primitives::solutions::SolutionPotVerifier for ShimTable {
60    fn is_proof_valid(seed: &PosSeed, s_bucket: SBucket, proof: &PosProof) -> bool {
61        let Some(correct_proof) = find_proof(seed, u32::from(s_bucket)) else {
62            return false;
63        };
64
65        &correct_proof == proof
66    }
67}
68
69impl Table for ShimTable {
70    const TABLE_TYPE: PosTableType = PosTableType::Shim;
71    #[cfg(feature = "alloc")]
72    type Generator = ShimTableGenerator;
73
74    fn is_proof_valid(seed: &PosSeed, s_bucket: SBucket, proof: &PosProof) -> bool {
75        <Self as ab_core_primitives::solutions::SolutionPotVerifier>::is_proof_valid(
76            seed, s_bucket, proof,
77        )
78    }
79}
80
81fn find_proof(seed: &PosSeed, challenge_index: u32) -> Option<PosProof> {
82    let quality = ab_blake3::single_block_hash(&challenge_index.to_le_bytes())
83        .expect("Less than a single block worth of bytes; qed");
84    if !quality[0].is_multiple_of(3) {
85        let mut proof = PosProof::default();
86        proof
87            .iter_mut()
88            .zip(seed.iter().chain(iter::repeat(quality.iter()).flatten()))
89            .for_each(|(output, input)| {
90                *output = *input;
91            });
92
93        Some(proof)
94    } else {
95        None
96    }
97}
98
99#[cfg(all(feature = "alloc", test, not(miri)))]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn basic() {
105        let seed = PosSeed::from([
106            35, 2, 52, 4, 51, 55, 23, 84, 91, 10, 111, 12, 13, 222, 151, 16, 228, 211, 254, 45, 92,
107            198, 204, 10, 9, 10, 11, 129, 139, 171, 15, 23,
108        ]);
109
110        let proofs = ShimTable::generator().create_proofs(&seed);
111
112        let s_bucket_without_proof = SBucket::from(1);
113        assert!(proofs.for_s_bucket(s_bucket_without_proof).is_none());
114
115        {
116            let s_bucket_with_proof = SBucket::from(0);
117            let proof = proofs.for_s_bucket(s_bucket_with_proof).unwrap();
118            assert!(ShimTable::is_proof_valid(
119                &seed,
120                s_bucket_with_proof,
121                &proof
122            ));
123        }
124    }
125}