Skip to main content

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