1#![no_std]
3#![expect(incomplete_features, reason = "generic_const_*")]
4#![warn(rust_2018_idioms, missing_debug_implementations, missing_docs)]
5#![feature(
6 const_block_items,
7 const_convert,
8 const_trait_impl,
9 funnel_shifts,
10 generic_const_args,
11 generic_const_items,
12 impl_restriction,
13 inherent_associated_types,
14 macroless_generic_const_args,
15 min_generic_const_args,
16 mut_restriction,
17 portable_simd,
18 step_trait
19)]
20#![cfg_attr(test, feature(float_erf))]
21#![cfg_attr(feature = "parallel", feature(exact_size_is_empty, sync_unsafe_cell))]
22#![cfg_attr(
23 feature = "alloc",
24 feature(iter_array_chunks, maybe_uninit_fill, ptr_as_uninit)
25)]
26
27pub mod chia;
28pub mod chiapos;
29pub mod shim;
30
31#[cfg(feature = "alloc")]
32extern crate alloc;
33
34#[cfg(feature = "alloc")]
35use ab_core_primitives::pieces::Record;
36use ab_core_primitives::pos::{PosProof, PosSeed};
37use ab_core_primitives::sectors::SBucket;
38use ab_core_primitives::solutions::SolutionPotVerifier;
39#[cfg(feature = "alloc")]
40use alloc::boxed::Box;
41#[cfg(feature = "alloc")]
42use core::fmt;
43#[cfg(feature = "alloc")]
44use core::hint;
45
46#[derive(Debug, Clone, Copy)]
48pub enum PosTableType {
49 Chia,
51 Shim,
53}
54
55#[derive(Debug)]
59#[cfg(feature = "alloc")]
60#[repr(C)]
61pub struct PosProofs {
62 pub mut(self) found_proofs: [u8; Record::NUM_S_BUCKETS / u8::BITS as usize],
70 pub mut(self) proofs: [PosProof; const { Record::NUM_CHUNKS }],
72}
73
74#[cfg(feature = "alloc")]
76impl PosProofs {
77 #[inline]
82 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
83 pub fn for_s_bucket(&self, s_bucket: SBucket) -> Option<PosProof> {
84 let proof_index = Self::proof_index_for_s_bucket(&self.found_proofs, s_bucket)?;
85
86 unsafe {
88 hint::assert_unchecked(proof_index < Record::NUM_CHUNKS);
89 }
90
91 Some(self.proofs[proof_index])
92 }
93
94 #[inline(always)]
95 #[cfg_attr(feature = "no-panic", no_panic::no_panic)]
96 fn proof_index_for_s_bucket(
97 found_proofs: &[u8; Record::NUM_S_BUCKETS / u8::BITS as usize],
98 s_bucket: SBucket,
99 ) -> Option<usize> {
100 let bits_offset = usize::from(s_bucket);
101 let found_proofs_byte_offset = bits_offset / u8::BITS as usize;
102 let found_proofs_bit_offset = bits_offset as u32 % u8::BITS;
103 let (found_proofs_before, found_proofs_after) =
104 found_proofs.split_at(found_proofs_byte_offset);
105 if (found_proofs_after[0] & (1 << found_proofs_bit_offset)) == 0 {
106 return None;
107 }
108 let proof_index = found_proofs_before
109 .iter()
110 .map(|&bits| bits.count_ones())
111 .sum::<u32>()
112 + found_proofs_after[0]
113 .unbounded_shl(u8::BITS - found_proofs_bit_offset)
114 .count_ones();
115
116 Some(proof_index as usize)
117 }
118}
119
120#[cfg(feature = "alloc")]
125pub trait TableGenerator<T: Table>:
126 fmt::Debug + Default + Clone + Send + Sync + Sized + 'static
127{
128 fn create_proofs(&self, seed: &PosSeed) -> Box<PosProofs>;
133
134 #[cfg(feature = "parallel")]
137 fn create_proofs_parallel(&self, seed: &PosSeed) -> Box<PosProofs> {
138 self.create_proofs(seed)
139 }
140}
141
142pub trait Table: SolutionPotVerifier + Sized + Send + Sync + 'static {
144 const TABLE_TYPE: PosTableType;
146 #[cfg(feature = "alloc")]
148 type Generator: TableGenerator<Self>;
149
150 fn is_proof_valid(seed: &PosSeed, s_bucket: SBucket, proof: &PosProof) -> bool;
152
153 #[cfg(feature = "alloc")]
155 fn generator() -> Self::Generator {
156 Self::Generator::default()
157 }
158}