ab_proof_of_space/
lib.rs

1//! Proof of space implementation
2#![no_std]
3#![expect(incomplete_features, reason = "generic_const_exprs")]
4#![warn(rust_2018_idioms, missing_debug_implementations, missing_docs)]
5#![feature(
6    const_convert,
7    const_trait_impl,
8    exact_size_is_empty,
9    float_erf,
10    generic_const_exprs,
11    get_mut_unchecked,
12    iter_array_chunks,
13    maybe_uninit_fill,
14    portable_simd,
15    ptr_as_ref_unchecked,
16    ptr_as_uninit,
17    step_trait,
18    sync_unsafe_cell
19)]
20
21pub mod chia;
22pub mod chiapos;
23pub mod shim;
24
25#[cfg(feature = "alloc")]
26extern crate alloc;
27
28#[cfg(feature = "alloc")]
29use ab_core_primitives::pieces::Record;
30use ab_core_primitives::pos::{PosProof, PosSeed};
31use ab_core_primitives::sectors::SBucket;
32use ab_core_primitives::solutions::SolutionPotVerifier;
33#[cfg(feature = "alloc")]
34use alloc::boxed::Box;
35#[cfg(feature = "alloc")]
36use core::fmt;
37
38/// Proof of space table type
39#[derive(Debug, Clone, Copy)]
40pub enum PosTableType {
41    /// Chia table
42    Chia,
43    /// Shim table
44    Shim,
45}
46
47// TODO: Return a single full proof and the rest as hashes instead to optimize memory usage and
48//  parallelize compute more easily
49/// Proof-of-space proofs
50#[derive(Debug)]
51#[cfg(feature = "alloc")]
52#[repr(C)]
53pub struct PosProofs {
54    /// S-buckets at which proofs were found.
55    ///
56    /// S-buckets are grouped by 8, within each `u8` bits right to left (LSB) indicate the presence
57    /// of a proof for corresponding s-bucket, so that the whole array of bytes can be thought as a
58    /// large set of bits.
59    ///
60    /// There will be at most [`Record::NUM_CHUNKS`] proofs produced/bits set to `1`.
61    pub found_proofs: [u8; Record::NUM_S_BUCKETS / u8::BITS as usize],
62    /// [`Record::NUM_CHUNKS`] proofs, corresponding to set bits of `found_proofs`.
63    pub proofs: [PosProof; Record::NUM_CHUNKS],
64}
65
66// TODO: A method that returns hashed proofs (with SIMD) for all s-buckets for plotting
67#[cfg(feature = "alloc")]
68impl PosProofs {
69    /// Get proof for specified s-bucket (if exists).
70    ///
71    /// Note that this is not the most efficient API possible, so prefer using the `proofs` field
72    /// directly if the use case allows.
73    #[inline]
74    pub fn for_s_bucket(&self, s_bucket: SBucket) -> Option<PosProof> {
75        let proof_index = Self::proof_index_for_s_bucket(self.found_proofs, s_bucket)?;
76
77        Some(self.proofs[proof_index])
78    }
79
80    #[inline(always)]
81    fn proof_index_for_s_bucket(
82        found_proofs: [u8; Record::NUM_S_BUCKETS / u8::BITS as usize],
83        s_bucket: SBucket,
84    ) -> Option<usize> {
85        let bits_offset = usize::from(s_bucket);
86        let found_proofs_byte_offset = bits_offset / u8::BITS as usize;
87        let found_proofs_bit_offset = bits_offset as u32 % u8::BITS;
88        let (found_proofs_before, found_proofs_after) =
89            found_proofs.split_at(found_proofs_byte_offset);
90        if (found_proofs_after[0] & (1 << found_proofs_bit_offset)) == 0 {
91            return None;
92        }
93        let proof_index = found_proofs_before
94            .iter()
95            .map(|&bits| bits.count_ones())
96            .sum::<u32>()
97            + found_proofs_after[0]
98                .unbounded_shl(u8::BITS - found_proofs_bit_offset)
99                .count_ones();
100
101        Some(proof_index as usize)
102    }
103}
104
105// TODO: Think about redesigning this API now that proofs are the output rather than tables
106/// Stateful table generator with better performance.
107///
108/// Prefer cloning it over creating multiple separate generators.
109#[cfg(feature = "alloc")]
110pub trait TableGenerator<T: Table>:
111    fmt::Debug + Default + Clone + Send + Sync + Sized + 'static
112{
113    /// Create proofs with 32 bytes seed.
114    ///
115    /// There is also `Self::create_proofs_parallel()` that can achieve higher performance and
116    /// lower latency at the cost of lower CPU efficiency and higher memory usage.
117    fn create_proofs(&self, seed: &PosSeed) -> Box<PosProofs>;
118
119    /// Almost the same as [`Self::create_proofs()`], but uses parallelism internally for better
120    /// performance and lower latency at the cost of lower CPU efficiency and higher memory usage
121    #[cfg(feature = "parallel")]
122    fn create_proofs_parallel(&self, seed: &PosSeed) -> Box<PosProofs> {
123        self.create_proofs(seed)
124    }
125}
126
127/// Proof of space kind
128pub trait Table: SolutionPotVerifier + Sized + Send + Sync + 'static {
129    /// Proof of space table type
130    const TABLE_TYPE: PosTableType;
131    /// Instance that can be used to generate tables with better performance
132    #[cfg(feature = "alloc")]
133    type Generator: TableGenerator<Self>;
134
135    /// Check whether proof created earlier is valid
136    fn is_proof_valid(seed: &PosSeed, s_bucket: SBucket, proof: &PosProof) -> bool;
137
138    /// Returns a stateful table generator with better performance
139    #[cfg(feature = "alloc")]
140    fn generator() -> Self::Generator {
141        Self::Generator::default()
142    }
143}